【我眼中的】 - 【5】闭包

1.什么是闭包?

在JavaScript中,函数内部可以读取全局变量,在函数外部却无法读取函数内的局部变量。

闭包指的是有权访问另外一个函数作用域中的变量的函数,也就是能够读取其他函数内部变量的函数。
闭包的本质是函数,有权访问另外一个函数作用域中的变量的函数

1
2
3
4
5
6
7
8
9
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999

上述代码中,函数f2定义在函数f1的作用域内,因此f1内部的局部变量对f2是可见的,但f2内部的局部变量对f1是不可见的。那么只要把f2作为f1的返回值,就可以在f1外部读取它的内部变量了。

⭐ 父对象的所有变量,对子对象都是可见的,反之则不成立。

1.1 闭包的作用

  • 使函数的内部变量(函数)在函数执行完后,仍然存活在内存中,延长了局部变量的生命周期
  • 将变量(函数)定义在闭包中使用,避免污染全局变量
  • 定义JS模块

1.2 闭包的缺点

函数执行完后,函数内的变量没有释放,占用内存时间会变长,容易造成内存泄露

2.闭包存在的问题

使用闭包的时候,①引用的变量可能发生变化 ②this指向的问题

2.1 引用变量的变化

1
2
3
4
5
6
7
8
9
10
11
12
function outer () {
var result = [];
for (var i = 0; i < 10; i++) {
result[i] = () => i
}
return result;
}

var x = outer();
for (var i = 0; i < 10; i++) {
console.log(x[i]());
}

因为每个闭包函数访问变量i是outer执行环境下的变量i,随着循环的结束,i已经变成10了,所以执行每个闭包函数,结果打印10, 10, …, 10。
解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
function outer () {
var result = [];
for (var i = 0; i < 10; i++) {
result[i] = function (num) {
return num;
}(i)
}
return result
}

var x = outer();
console.log(x); // [0, 1, 2, 3, 4,5, 6, 7, 8, 9]

此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样。

2.2 this的指向

1
2
3
4
5
6
7
8
9
var object = {
name: "object"
getName: function() {
return function() {
console.info(this.name)
}
}
}
object.getName()() // underfined

因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows,打印undefined。

解决方案:

1
2
3
4
5
6
7
8
9
10
11
var name = "The Window";
var object = {
name : "My Object",
getName : function(){
var that = this;
return function(){
console.info(this.name)
};
}
};
object.getName();

使用that指向object,指定了匿名函数调用时的this指向对象。

闭包会使得 函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

同时闭包会在 父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

文章作者: qinwei
文章链接: https://qw-null.github.io/2022/04/24/5-我眼中的-闭包/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 QW's Blog