[js] 闭包
为了转用markdown编辑器,原先类似的老文章不再更新,新的往这里写了。
闭包就是在函数中使用的未在函数中定义的但在函数所处上下文有效的变量(标识符)与函数本体的集合。
function spyOn(func) {
let count = 0;
let arr = [];
let result;
let spy = function (...args) {
count++;
arr.push(...args);
//val = func.apply(this, args);//参数复用
result = func(...args);//参数复用
return result;
}
spy.callCount = () => {
return count;
}
spy.wasCalledWith = (x) => {
return arr.indexOf(x) != -1;
}
spy.returned = (x) => {
return x === result;
}
return spy
}
function adder(n1, n2) { return n1 + n2; }
let adderSpy = spyOn( adder );
adderSpy(2, 4); // returns 6
adderSpy(3, 5); // returns 8
adderSpy.callCount(); // returns 2
adderSpy.wasCalledWith(4); // true
adderSpy.wasCalledWith(0); // false
adderSpy.returned(8); // true
adderSpy.returned(0); // false
函数可以记住并访问所在的词法作用域时,
即使函数是在当前词法作用域之外执行,
这时就产生了闭包。
在foo()执行后,通常会期待foo()的整个内部作用于都被销毁,因为引擎有垃圾回收机制来释放不再使用的内存空间。
由于看上去foo()的内容不会再被使用,所以很自然地会考虑对其进行回收。
但是,闭包可以阻止这件事情发生。
事实上内部作用域依然存在,因此,没有被回收,bar()仍在使用内部作用域。
由于bar()声明在foo()函数内部,所以它拥有涵盖foo()内部作用域的闭包,
使得该作用域能够一直存活,以便bar()在以后的任何时间进行引用。
bar()函数在foo()调用完成后,依旧持有对其作用域的引用,而这个引用就叫做闭包。
function foo(){
var a = 2;
function bar(){
console.log(a);
}
return bar;
}
var baz = foo();
baz(); //2//这就是闭包的效果
function foo(){
var a = 2;
function baz(){
console.log(a)
}
bar(baz);
}
function bar(fn){
fn(); //这就是闭包
}
foo();//2
function wait(message){
setTimeout(function time(){
console.log(message);
}, 1000);
}
wait("hello clousre");//hello clousre
for (var i = 1; i < 6; i++) {
console.log(i)
}
//1
//2
//3
//4
//5
for (var i = 1; i < 6; i++) {
setTimeout(function time() {
console.log(i)
}, i * 1000)
}
//6
//6
//6
//6
//6
//闭包的使用
for(var i=1; i<6; i++){
(function(j){
setTimeout(function time(){
console.log(j)
}, j*1000)
})(i);
}
//1
//2
//3
//4
//5
块作用域
本质上来讲它是将一个块转换成可以被关闭的作用域。
for(var i=1; i<6; i++){
let j = i; //闭包的块作用域
setTimeout(function time(){
console.log(j)
}, j*1000)
}
//1
//2
//3
//4
//5
它会指出变量在循环过程中不止被声明一次,每次迭代都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
for(let i=1; i<6; i++){
setTimeout(function time(){
console.log(i)
}, i*1000)
}
//1
//2
//3
//4
//5