闭包是一种特殊的对象。

它由两部分组成。执行上下文(代号A),以及在该执行上下文中创建的函数(代号B)。

当B执行时,如果访问了A中变量对象中的值,那么闭包就会产生。

在大多数理解中,包括许多著名的书籍,文章里都以函数B的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。

我们只需要知道,一个闭包对象,由A、B共同组成,在以后的篇幅中,我将以chrome的标准来称呼。

// demo01
function foo() {
    var a = 20;
    var b = 30;

    function bar() {
        return a + b;
    }

    return bar;
}

var bar = foo();
bar();

在上面的例子中,首先有执行上下文foo,在foo中定义了函数bar,而通过对外返回bar的方式让bar得以执行。当bar执行时,访问了foo内部的变量a,b。因此这个时候闭包产生。

在chrome中通过断点调试的方式可以逐步分析该过程,从下图可以看出,此时闭包产生,用foo代指。

上图中,红色箭头所指的正是闭包。其中Call Stack为当前的函数调用栈,Scope为当前正在被执行函数的作用域链,Local为当前活动对象。

断点调试的方式在下一章中讲解

在学习了闭包的基础概念,为了验证一下大家是否真的理解了,现在大家来思考一个小问题。我们将demo01的代码稍作调整,大家来思考一下,是否形成了闭包。

// demo02
function foo() {
    var a = 20;
    var b = 30;

    function bar() {
        return a + b;
    }

    bar();
}

foo();

仍然是foo中定义的bar函数在执行时访问了foo中的变量。因此这个时候仍然会形成闭包。如图所示。

那么我们再来看一个非常有意思的例子。

// demo03
function add(x) {
    return function _add(y) {
        return x + y;
    }
}

add(2)(3); // 5

这个例子有闭包产生吗?

当然有。当内部函数_add被调用执行时,访问了add函数变量对象中的x。因此这个时候,闭包会产生。如图所示。一定要记住,函数参数中的变量传递进入函数之后也会加入到变量对象中。

还有一个例子可以验证大家对于闭包的理解。

我们来看看下面这段代码中是否有闭包产生。

// demo04
var name = "window";

var p = {
    name: 'Perter',
    getName: function() {
        return function() {
            return this.name;
        }
    }
}

var getName = p.getName();
var _name = getName();
console.log(_name);

getName在执行时,它的this其实指向的是window对象,因此这个时候并没有形成闭包的环境,因此这个例子没有闭包。

那么如果我按照下面的方式进行改动呢?

// 改动一
// demo05
var name = "window";

var p = {
    name: 'Perter',
    getName: function() {
        return function() {
            return this.name;
        }
    }
}

var getName = p.getName();

// 利用call的方式让this指向p对象
var _name = getName.call(p);
console.log(_name);
// 改动二
// demo06
var name = "window";

var p = {
    name: 'Perter',
    getName: function() {

        // 利用变量保存的方式保证其访问的是p对象
        var self = this;
        return function() {
            return self.name;
        }
    }
}

var getName = p.getName();
var _name = getName();
console.log(_name);

分别利用call与变量保存的方式保证this指向都为p对象,那么它们哪一个产生了闭包,哪一个没有产生闭包呢?这里就留一个思考题,大家可以根据上面的概念进行分析。为了验证你们自己的分析是否正确,大家可以学习后续章节中如何在chrome开发者工具中查看闭包。

后续章节会详细学习this的指向问题

results matching ""

    No results matching ""