前言
这篇文字简单的实现了define
方法,了解闭包
的使用场景.
君子爱才,取之有道
近期在使用Array的sort api排序的遇到了问题,所以花了些时间研究它,这里记录下供参考。
1 |
|
上面的例子很简单,大家在日常业务中应该会用到,结果也显而易见,把 ary
按降序排列;如果改变排序条件prev - nex > 0 ? 1 : -1
, 结果就会变成把ary
按升序排列。
最近在和新同事的沟通中被问到了javascript是如何管理内存的,以前虽有了解过,但没有系统的记忆,所以答的不理想,乘此机会在这里尽可能整理记忆下。
定义内存就是暂时存储程序和数据的地方。程序语言中低级语言一般都有低级的内存管理接口供开发者有选择性的释放内存,如C语言。高级语言则在创建变量时选择性的分配内存,然后在不使用的时候释放自动释放,这种『垃圾回收』机制并不意味着在高级语言开发中可以不顾内存管理因素肆意滥用。
大体了解一个框架可以从生命周期入手,如React,Vue。其实了解任何已被定义的事物都可以如此。程序语言中的内存生命周期大体一致:
javascript中分堆内存和栈内存。
堆内存
堆内存用于存放new创建的对象和数组,因为javascript无法确定声明的函数或者数组对象的具体内存大小,所以无法存放在栈内。它是由虚拟机自动垃圾回收来管理。通常会在栈中定义一个特殊变量,这个变量的取值等于数组或者对象在堆内存中的地址,这就创建了引用变量。数组和对象本身在堆中的分配即时程序在运行到new产生数组和对象的代码块之外,也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,但只是不能被使用,仍然占用着堆内存,在随后的一个不确定时间被回收。
1 | var o = { |
栈内存
基本类型的变量和对象都是在栈内存中分配。当在一个代码块中定义一个变量时,系统就为这个变量分配内存空间,在当前作用域不包含此变量时,释放栈内存空间。
1 | var n = 1; // 给数值变量分配内存 |
近一个月开始着手用React重构项目,从0开始到最终成型,从无头绪到摸到套路还是挺坎坷的,有必要把所有的思考在这里记录。
原先的项目是用jquery写的,业务逻辑不复杂,总的就是取数据做展示。抽象出了若干组件:
Jest-1,Jest-2,Jest-3三节介绍了基本API用法,在介绍测试React/Vue之前,我们先来一餐Jquery的业务场景小试牛刀。
简单的登录页面,要求有这么几个:
本节介绍了异步测试的代码,是不是可以开始实际业务情景测试了?当然可以,但是Jest并不止这些内容。下节先介绍Jquery业务场景的登录测试。
Jest-1、Jest-2分别讲了断言基础和Mock基础,满足了大部分同步测试的需求。这节主要描述异步测试的情况,主要场景是回调、Promise以及async/await:
1 | /** __mocks__/requestfks.js **/ |
1 | /** requestfks.js **/ |
1 | /** user.js **/ |
这里引用官网的例子,重点是要引入内置参数done:1
2
3
4
5
6
7
8
9test('the data is peanut butter', done => {
function callback(data) {
expect(data).toBe('peanut butter');
// 在回掉执行完成时调用done方法通知Jest异步过程结束
done();
}
fetchData(callback);
});
1 | const resolveFunc = jest.fn((d) => { |
1 | jest.mock('../requestfks') |
本节介绍了异步测试的代码,是不是可以开始实际业务情景测试了?当然可以,但是Jest并不止这些内容。下节先介绍Jquery业务场景的登录测试。
Jest-1主要讲述了Jest冢对Expect的用法,这篇Jest-2将讲述重要的mock部分
单元测试的主要做的事情给予我们想给的,得到我们期望的。现在的业务代码中都是由各个模块串联而成,你包我,我包他,一个包可能很大很长,但最终会抛出公共接口。我们在测试引入包时,不需关心内部具体实现,这时可以使用Mock功能,直接给出期望的结果。
除主测之外的代码,都可以Mock。
在上一篇中的Function里也提到jest.fn,这里细说:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48it('mockFn.mock.calls', () => {
const f = jest.fn()
f(1, 2)
f(2, 3)
// 调用过程存入集合
expect(f.mock.calls).toEqual(expect.arrayContaining([[1, 2], [2, 3]]))
})
it('mockFn.mock.instances', () => {
const f = jest.fn()
const a = new f()
const b = new f()
// 引用计数
expect(f.mock.instances[0]).toBe(a)
})
it('mockFn.mockClear', () => {
function f() {
return 3
}
f = jest.fn(()=>4)
const a = new f()
const b = new f()
f(2)
expect(f.mock.calls[2]).toEqual([2])
// 清空执行轨迹
f.mockClear()
expect(f.mock.instances).toEqual([])
expect(f.mock.calls).toEqual([])
// f.mockRestore()
// 重置mock.fn
f.mockReset()
expect(f()).toBeUndefined()
})
it('mockFn.mockImplementationOnce', () => {
var myMockFn = jest.fn()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false))
// 可逐一调用
expect(myMockFn((err, val) => val)).toBeTruthy()
expect(myMockFn((err, val) => val)).toBeFalsy()
expect(myMockFn()).toBeUndefined()
})
it('mockFn.mockReturnValueOnce', () => {
const myMockFn = jest.fn()
// 只执行一次,后重置
myMockFn.mockReturnValueOnce(90)
expect(myMockFn()).toBe(90)
expect(myMockFn()).toBeUndefined()
})
jest.fn是单个函数的模拟,一个具体的Module可能会抛出多个接口,同样可以模拟:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18jest.mock('../request', (url) => {
let users = {
4: {name: 'Mark'},
5: {name: 'Paul'}
}
return new Promise((resolve, reject) => {
if (url) {
const userId = url.substr('/users/'.length)
process.nextTick(
() => users[userId]
? resolve(users[userId])
: reject({
error: 'User with '+ userId +' not found.'
})
)
}
})
})
还有一种形式:1
2
3jest.mock('../request')
// 接下来针对需要自定义的方法单独jest.fn
jest.default = jest.fn()
计时器经常在业务中用到,setTimeout
,setInterval
,clearTimeout
,clearInterval
;要是在测试中按真实的设置等下去那就疯啦,所以facebook的天才们提供了模拟方案,即做了延迟处理又不用等多时:1
2
3
4
5
6
7
8
9
10// 启用timer mock
jest.useFakeTimers()
// 调用全部timer mock
jest.runAllTimers()
// 运行pending中的timers,如一个定时器(1000)的回调触发了另一个定时器,这个后触发的定时器(10000ms)处于pending
jest.runOnlyPendingTimers()
// 快进
jest.runTimersToTime(1000)
// 清空pending的timers
jest.clearTimers()
以上讲了function mock、class mock以及timers mock的种种api,在实际测试环境中出场率还是挺高的。接下一节将介绍异步检测,非常重要哟。
本系列内容基本上按照官网的示例来讲解如何入门。
首先讲匹配器,是单元测试最基础的部分,一般称为断言,如:assert,tap,chai,should等断言库。Jest内置了断言库,正式场景中不需引入断言库。
我们从基本类型讲起,
1 | it('"" toBe ""', () => { |
1 | it('12 toBe 12', () => { |
1 | test('[1,2,3,4,500] not toBe [1,2,3,4,500]', () => { |
1 | it('false toBeFalsy', () => { |
1 | function sum(a) { |
1 | it('{hello: "world"} toHaveProperty hello', () => { |
1 | it('undefined toBeUndefined', () => { |
以上总的讲述了Expect基本的使用API,接下来讲一讲另一个重要的方法mock。
HTML
1 | <div contentEditable=true data-ph="My Placeholder String"></div> |
CSS
1 | [contentEditable=true]{ |