1 闭包和作用域链
- 闭包初步引入
//以下是一些例子
//个人理解:凡是外部变量接收一个return的函数,比如let a=hd(),那么和该函数同级的变量以及父级的变量都会被这个外部变量绑定(相当于这块内存空间直接给了外部变量)
//凡是函数调用一次,都会开辟一块新的内存空间
//没有被绑定的变量会被js垃圾回收机制自动清除
function hd () {
let n = 1
return function () {
console.log(++n)
}
}
let a = hd()
a() //2
a() //3
let b = hd()
b() //2
hd()() //2
hd()() //2
function hd2 () {
let n = 1
return function () {
let m = 1
return function () {
console.log(++n)
console.log(++m)
}
}
}
let c = hd2()()
c() //2 2
c() //3 3
function hd3 () {
let n = 1
return function () { //注意n被绑定给了b,而m没有
let m = 1
function show () {
console.log(++m)
console.log(++n)
}
show()
}
}
let d = hd3()
d() //2 2
d() //2 3
- 考虑构造函数
function test () {
let a = 1
this.sum = function () {
console.log(++a)
}
}
let obj = new test()
obj.sum() //2
obj.sum() //3
//上面的构造函数等价于
function test2 () {
let a = 1
return function sum () {
console.log(++a)
}
}
let obj2 = test2() //可以写成let obj2 = new test2()
obj2() //2
obj2() //3
- 区分var和let
let arr = []
for (var i = 1; i <= 3; i++) {
arr.push(function () {
return i
})
}
console.log(arr[0]()) //4
let arr2 = []
for (let i = 1; i <= 3; i++) {
arr2.push(function () {
return i
})
}
console.log(arr2[0]()) //1
let arr3 = []
for (var i = 1; i <= 3; i++) {
(function (i) {
arr3.push(function () { //通过立即执行函数开辟内存空间,绑定i给arr3.push方法
return i
})
})(i)
}
console.log(arr3[0]()) //1
- 作用域链(顺带复习一下this)
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
}
};
console.log(object.getNameFunc()()); //The Window
var name2 = "The Window";
var object2 = {
name: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
}
};
console.log(object2.getNameFunc()()); //My Object
- 闭包就是一个函数,能够访问其他函数内部变量的函数
- 闭包的优点
访问其他函数内部变量,变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期,避免定义全局变量所造成的污染 - 闭包的缺点
由于闭包会将它的外部函数的作用域也保存在内存中,因此会比其他函数更占用内存,这样的话,如果过度使用闭包,就会有内存泄露的威胁 - 解决闭包引起的内存泄露
在退出函数之前,将不使用的局部变量全部删除,可以使变量赋值为null
避免变量的循环赋值和引用
由于jQuery考虑到了内存泄漏的潜在危害,所以它会手动释放自己指定的所有事件处理程序。只要坚持使用jQuery的事件绑定方法,就可以一定程度上避免这种特定的常见原因导致的内存泄漏 - 闭包的使用场景
封装功能时(需要使用私有的属性和方法),函数防抖、函数节流、函数柯里化、给元素伪数组添加事件需要使用元素的索引值。
2 总结
以上就是闭包和作用域链基础