作者:Blue_zns 链接:juejin.cn/post/688815… 来源:掘金
闭包是函数和周围状态(词法环境)的组合,闭包使你可以访问外层函数的作用域,每创建一个函数闭包同时也被创建.
JavaScript中,每个函数都会创建自身的闭包 闭包没有所谓"用处"或者"好坏",闭包是JS本身的一部分,你喜欢也好不喜欢也好,它就在那里 (function (){})()不是闭包,这是个自执行函数
闭包给了函数访问外部变量的能力,并将函数与外部变量(函数的环境)绑定在一起
作用域,就是一个东西(变量、函数、其他)起作用的范围
局部变量,就像函数的私有财产,局部变量只能在定义它的函数内使用
在JS中,子函数可以直接使用父函数的局部变量,
垃圾回收
内存泄露:内存泄露是指你「用不到」(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
作用域决定了谁是垃圾,变量其实并没有被立即回收,而是被标记为"可回收",在下一次GC工作时被带走
函数的存在,延长了外层局部变量的生存周期,只要这个onclick函数还在,那么它(onclick函数)外面的局部变量就不会回收
js怎么知道你用了哪些局部变量的?要保留哪些局部变量不回收?
js不需要确定,它直接保留全部父级变量,用没用到都保留,健壮性,性能考虑
js如何确定onclick消失后要回收哪些变量?
引用计数机制.标明一个东西,在被几个人引用,一旦引用计数归零,则被标记为"可回收".内部函数对外层局部变量的引用会计算在引用计数中.
父级的变量不回收,那父级的父级呢?
闭包的存在,不仅延长父级的局部变量有效期,父级的父级、父级的父级的父级...一直到全局的,其实都会延长
---
闭包是js自身语法的一部分,只要你访问了父函数的局部变量,都算是"用到了"闭包,这是一个自然的过程,无需刻意使用
闭包保证了js自身的运行,如果错误的将外部变量回收掉,会导致js崩溃,所以闭包更多的是为js语言本身服务,而不是我们
---
性能方面:拆分函数,块级作用域
实例:
私有成员
(function() {
let name = 'blue'; //这个变量,是任何人从外部都访问不到的
})();
(function() {
let name = 'blue';
//Box中的方法可以访问name,因为"闭包"
class Box {
get name() {
return name;
}
set name(val) {
//如果需要,可以校验一下val
name = val;
}
}
})();
//2-接收这个class,以便在外部使用
const Box = (function() {
let name = 'blue';
//1-不直接暴露name,而是class出去
return class {
get name() {
return name;
}
set name(val) {
name = val;
}
}
})();
let box = new Box();
//3-妄图直接使用name
name = 'xxx'; //报错
//4-只能通过setter来访问
box.name = 'name2'; //正确
作者:Blue_zns
链接:https://juejin.cn/post/6888150116138483719
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
let和var在循环中的区别
//完全等价于
var i = 0;
{
aBtn[i].onclick = function() {
alert(i);
};
i++;
}
{
aBtn[i].onclick = function() {
alert(i);
};
i++;
}
{
aBtn[i].onclick = function() {
alert(i);
};
i++;
}
作者:Blue_zns
链接:https://juejin.cn/post/6888150116138483719
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
因为onclick执行时,i早就加到3了,所以不是3才奇怪
//let带有块级作用域
//"大家一人一个i,谁也别跟别人抢哈"
{
let i=0;
aBtn[i].onclick = function() {
alert(i);
};
}
{
let i=1;
aBtn[i].onclick = function() {
alert(i);
};
}
{
let i=2;
aBtn[i].onclick = function() {
alert(i);
};
}
作者:Blue_zns
链接:https://juejin.cn/post/6888150116138483719
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
每次循环都是一个新的代码块,在事件被触发时,var声明的已经加到3,关键是触发时机的延后(并且共用同一个i),而let是每个代码块独立的
每个函数内部局部变量是独立的
let aBtn = document.querySelectorAll('button');
for (var i = 0; i < aBtn.length; i++) {
//参数,其实相当于一个局部变量,从而达到一人一个index的目的
(function(index) {
aBtn[index].onclick = function() {
alert(index);
};
})(i);
}
作者:Blue_zns
链接:https://juejin.cn/post/6888150116138483719
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我们可以让参数也叫i,这没什么,参数和外部变量同名没关系的
let aBtn = document.querySelectorAll('button');
for (var i = 0; i < aBtn.length; i++) {
//不用找哈,只有参数名字变了
(function(i) {
aBtn[i].onclick = function() {
alert(i);
};
})(i);
}
作者:Blue_zns
链接:https://juejin.cn/post/6888150116138483719
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
闭包=函数+外层变量 闭包的第一重含义:子函数可以访问父函数的局部变量 闭包的第二重含义:子函数的存在,延长了外层变量的生存周期(垃圾回收、引用计数)
闭包是JS自身语法的一部分,99%的情况下不需要刻意使用它,它一直在发挥作用 优化建议:注意所有子函数,都会延长父级变量的存在时间(图片等大型数据对象的性能问题)