jQuery技术

前端进阶(十一):详细图解jQuery对象(7)

字号+ 作者:H5之家 来源:H5之家 2017-04-07 17:03 我要评论( )

接下来,我们借助一些实例,来使用断点调试工具,看一看,我们的demo函数,在执行过程中的具体表现。 // demo01var fn;function foo() {var a = 2;function baz() {console.log( a );}fn = baz; }function bar() {f

接下来,我们借助一些实例,来使用断点调试工具,看一看,我们的demo函数,在执行过程中的具体表现。

// demo01 var fn; function foo() { var a = 2; function baz() { console.log( a ); } fn = baz; } function bar() { fn(); } foo(); bar(); // 2

在向下阅读之前,我们可以停下来思考一下,这个例子中,谁是闭包?

这是来自《你不知道的js》中的一个例子。由于在使用断点调试过程中,发现chrome浏览器理解的闭包与该例子中所理解的闭包不太一致,因此专门挑出来,供大家参考。我个人更加倾向于chrome中的理解。

  • 第一步:设置断点,然后刷新页面。


  • 设置断点

  • 第二步:点击上图红色箭头指向的按钮(step into),该按钮的作用会根据代码执行顺序,一步一步向下执行。在点击的过程中,我们要注意观察下方call stack 与 scope的变化,以及函数执行位置的变化。

  • 一步一步执行,当函数执行到上例子中


    baz函数被调用执行,foo形成了闭包

    我们可以看到,在chrome工具的理解中,由于在foo内部声明的baz函数在调用时访问了它的变量a,因此foo成为了闭包。这好像和我们学习到的知识不太一样。我们来看看在《你不知道的js》这本书中的例子中的理解。


    你不知道的js中的例子

    书中的注释可以明显的看出,作者认为fn为闭包。即baz,这和chrome工具中明显是不一样的。

    而在备受大家推崇的《JavaScript高级编程》一书中,是这样定义闭包。


    JavaScript高级编程中闭包的定义


    书中作者将自己理解的闭包与包含函数所区分

    这里chrome中理解的闭包,与我所阅读的这几本书中的理解的闭包不一样。具体这里我先不下结论,但是我心中更加偏向于相信chrome浏览器。

    我们修改一下demo01中的例子,来看看一个非常有意思的变化。

    // demo02 var fn; var m = 20; function foo() { var a = 2; function baz(a) { console.log(a); } fn = baz; } function bar() { fn(m); } foo(); bar(); // 20

    这个例子在demo01的基础上,我在baz函数中传入一个参数,并打印出来。在调用时,我将全局的变量m传入。输出结果变为20。在使用断点调试看看作用域链。


    闭包没了,作用域链中没有包含foo了。

    是不是结果有点意外,闭包没了,作用域链中没有包含foo了。我靠,跟我们理解的好像又有点不一样。所以通过这个对比,我们可以确定闭包的形成需要两个条件。

  • 在函数内部创建新的函数;

  • 新的函数在执行时,访问了函数的变量对象;

  • 还有更有意思的。

    我们继续来看看一个例子。

    // demo03 function foo() { var a = 2; return function bar() { var b = 9; return function fn() { console.log(a); } } } var bar = foo(); var fn = bar(); fn();

    在这个例子中,fn只访问了foo中的a变量,因此它的闭包只有foo。


    闭包只有foo

    修改一下demo03,我们在fn中也访问bar中b变量试试看。

    // demo04 function foo() { var a = 2; return function bar() { var b = 9; return function fn() { console.log(a, b); } } } var bar = foo(); var fn = bar(); fn();


    这个时候闭包变成了两个

    这个时候,闭包变成了两个。分别是bar,foo。

    我们知道,闭包在模块中的应用非常重要。因此,我们来一个模块的例子,也用断点工具来观察一下。

    // demo05 (function() { var a = 10; var b = 20; var test = { m: 20, add: function(x) { return a + x; }, sum: function() { return a + b + this.m; }, mark: function(k, j) { return k + j; } } window.test = test; })(); test.add(100); test.sum(); test.mark(); var _mark = test.mark; _mark();


    add执行时,闭包为外层的自执行函数,this指向test


    sum执行时,同上


    mark执行时,闭包为外层的自执行函数,this指向test


    _mark执行时,闭包为外层的自执行函数,this指向window

    注意:这里的this指向显示为Object或者Window,大写开头,他们表示的是实例的构造函数,实际上this是指向的具体实例

    test.mark能形成闭包,跟下面的补充例子(demo07)情况是一样的。

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 前端基础进阶(十一):详细图解jQuery对象,以及如何扩展jQuery

      前端基础进阶(十一):详细图解jQuery对象,以及如何扩展jQuery

      2017-03-25 10:00

    网友点评
    n