JavaScript闭包与for循环产生的化学反应

1,797 阅读3分钟

一,闭包

一句话: 闭包就是一个作用域链的问题,能够访问其它函数内部变量 的函数叫做闭包! 引用用阮一峰老师的一句话: 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁 ! 下面来看下关于闭包的小栗子:

dom01

function fn() {
    var a = 2;
    function fx() {
        console.log(a);
    }
    return fx;
}
var result = fn();
result();	// 2

1.函数fn()内部定义了一个局部变量a,和一个函数fx();

2.fn()的返回值是fx()这个函数;

3.当调用fn()函数时,fn()的返回值是fx()函数,然后定义一个变量result保存起来;

4.这时result是一个函数,result()就调用了这个函数;

5.函数result()发生调用被执行,就打印出2;

结论:函数fx就是闭包!

二,for循环+闭包

for循环就不必多说了,直接看dom!

dom02

for (var i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}

dom02结果肯定是6 6 6 6 6了,这里也涉及到了同步和异步的问题:

1.每一次for循环都会产生一个异步任务定时器;

2.它会放在任务队列中等同步任务执行完后再去执行;

3.当i等于6时,i<=5不成立,跳出for循环;

4.此时i的值为6,有5个定时器就打印出5个6了!

dom03

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}

dom03因为let具有块级作用域,每循环一次就会产生一个单独的作用域,所以打印出来就是1 2 3 4 5了!

dom04

for (var i = 1; i <= 5; i++) {
    (function () {
        var j = i;
        setTimeout(function timer() {
            console.log(j);
        }, j * 1000);
    })();
}

dom04就是一个闭包的栗子了,每循环一次i变量的值就会被保存起来,因为每次循环i的值都会被保留给下面定时器函数用,不会被垃圾机制回收,所以打印出来就是1 2 3 4 5了!

dom05

我们对dom04的栗子做了一下小小的改进:

for (var i = 1; i <= 5; i++) {
    (function (i) {
        setTimeout(function timer() {
            console.log(i);
        }, i * 1000);
    })(i);
}

三.关于闭包的思考题

下面两个思考题都是摘自阮一峰老师的,如果你能做出来并讲解就能彻底明白闭包了!

dom06

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        return function () {
            return this.name;
        };
    }
};
alert(object.getNameFunc()());

dom06栗子中有一个情况需要考虑,就是this指向问题:

1.在object中getNameFunc这个函数中this是指向object的;

2.getNameFunc函数中返回值又是一个函数,它里面的this指向的是window;

3.当object.getNameFunc()调用时,它的返回值是function () { return this.name };

4.当object.getNameFunc()()调用时,它的返回值是this.name;

5.这时this.name指向的就是window.name,var name = "The Window"是定义的全局,所以object.getNameFunc()()就会弹出The Window;

dom07

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        var that = this;
        return function () {
            return that.name;
        };
    }
};
alert(object.getNameFunc()());

dom07和dom06中有一个不同就是getNameFunc函数中,把this保存给了that!

1.当object.getNameFunc()()调用时,它的返回值是that.name

2.前面this指的是object,而var that = this,故that.name就是My Object;

这时就形成了闭包!