求解,看了下 js 的闭包,有些地方不太明白 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
cheroky
V2EX    Javascript

求解,看了下 js 的闭包,有些地方不太明白

  •  
  •   cheroky 2017-05-21 23:17:22 +08:00 3444 次点击
    这是一个创建于 3094 天前的主题,其中的信息可能已经有所发展或是发生改变。

    《 Javascript 高级程序设计》讲闭包的一章中,有这么一个例子

    var name = "The Window"; var object = { name: "My Object", getName: function() { return function() { console.log(this.name) } } } object.getName()(); // "The Window" 

    我很好奇,然后我又加上了另外一个函数,测试一下

    function object2() { this.name = "My"; return function() { console.log(this.name); } } object2()(); // "My" 

    第二个函数正常输出了 My,为什么??书上说是“内部函数搜 this 跟 arguments 是不会访问到外部变量的”,可是第二个例子又作何解释??然后我又把 this.name 赋值去掉:

    function object2() { return function() { console.log(this.name); } } object2()(); // "The Window" 

    这个时候跟第一个例子相同了,也就是外部函数的 this.name 没这个值得时候,内部函数的 this 会指向 window。于是我又把第一例子改了一下:

    var name = "The Window"; var object = { name: "My Object", getName: function() { console.log(this.name); //console.log(this); return function() { console.log(this.name); } } } object.getName()(); // "My Object","The Window" 

    然后我尝试输出了 getName() 里面的 this。发现指向的是 object。。。而其余两个 this 输出都是 Window 的一长串东西。我感觉被 this 跟闭包搞晕了。。。

    12 条回复    2017-05-22 14:39:41 +08:00
    ferrum
        1
    ferrum  
       2017-05-21 23:50:13 +08:00
    唉哟好长,后面的没看,就说第二个函数。

    第二个函数`object2`,里面的`this`就是指向`window`,当你`this.name = "my"`时,你实际上是在`window`变量上定义了一个`name`属性。
    wangjie
        2
    wangjie  
       2017-05-22 00:03:03 +08:00   1
    lijsh
        3
    lijsh  
       2017-05-22 00:18:33 +08:00   1
    第一个例子和第四个例子有可比性,因为都是在 object 上定义属性和方法;正常情况下你在对象的方法中访问 this,是会指向这个对象的(也就是 object ),这也是你第四个例子第一个 console.log(this.name)输出'My Obejct'、第二个 console.log(this)会指向 object 的原因;
    但是 getName 方法里又定义了一个函数(闭包),闭包里的 this 会丢失,自动指向全局,这就是第四个例子里最后一个 console.log(this)输出 window 的原因。

    第二和第三个例子只是单纯的函数,没有绑定为对象的方法,所以 this 就是 window。最搞笑的是第二个例子,你本来赋值 this.name = 'My'本身就是给 window 赋值,所以后面拿回来的自然也是这个值。
    lijsh
        4
    lijsh  
       2017-05-22 00:19:43 +08:00
    更正:“……自动指向全局,这就是第四个例子里最后一个 console.log(this.name)输出‘ The Window ’” 的原因。
    seki
        5
    seki  
       2017-05-22 00:24:41 +08:00
    this 指向的是函数的调用者
    SuperMild
        6
    SuperMild  
       2017-05-22 00:30:42 +08:00 via iPhone   1
    this 和闭包是两套东西,变量受闭包影响,但 this 不受闭包影响。总之,this 和闭包不要混在一起看,会很混乱。
    SuperMild
        7
    SuperMild  
       2017-05-22 00:32:35 +08:00 via iPhone
    单独理解 this 的规则就好,看 you don't know is
    sensui7
        8
    sensui7  
       2017-05-22 01:32:33 +08:00   1
    可以放弃 望远镜那本书了, 虽然经典, 已经落伍了. JS 的发展太快.
    闭包就是一个引用另一个作用域里变量的函数.

    ```js
    var name = "The Window";
    var object = {
    name: "My Object",
    getName: function() {
    return function() { // 这个函数其实不算是闭包, 因为它唯一使用的变量是存在于全局环境的, 讨论闭包是无意义的
    console.log(this.name)
    }
    }
    }
    object.getName()(); // "The Window"
    ```

    再说 this 取值,
    1. 函数中的 this 要么是 window(浏览器)要么是 undefined, 这取决于是否是 strict 模式
    你的前 3 个都是函数中的 this, 所以都是 window

    2. 方法中的 this, 是方法的 recevier, 所以第 4 个例子中的 getName 的 this 是 object, 至于它返回的函数, 那个只是函数, 并不是方法调用.

    this 最让人迷惑的地方, 它不是基于词法的, 是运行时决定的.

    var object = {
    name: "My Object",
    getName: function() {
    console.log(this.name);
    //console.log(this);
    return function foo () {
    console.log(this.name); // 这个 this 看起来在 object 内部, 但是 this 跟你把它写在哪里无关, 要看你在哪里使用
    }
    }
    }

    obect.getName()() // 这行表达式最终相当于执行了一次普通函数调用, 函数调用 this 的值是全局对象
    object.getName().call(object) // 这里我们强制指定 foo 的 this 为 object, 它输出'My Object'
    这就能体现 this 跟你把它写在哪里是无关的, 要看你如何调用.
    另外, es6 的箭头函数的 this 就是基于词法的, 只跟你把函数定义在哪有关, 不用担心调用时 this 的取值问题.
    Biwood
        9
    Biwood  
       2017-05-22 09:23:52 +08:00 via Android   1
    楼上几个没说到点上,关键词:Javascript Context

    你在讨论 this 的时候跟闭包无关,但是跟函数的**执行环境**有关

    一般而言
    对于:

    A.foo()

    A.foo 引用的函数的 Context 是 A,所以函数里的 this 指向 A。

    对于:

    foo()

    等价于

    window.foo()

    所以 foo 里面的 this 指向 wondow。

    那么:

    object.getName()()

    等价于

    window.foo = object.getName() // Context 是 object
    window.foo() // ontext 是 window
    wensonsmith
        10
    wensonsmith  
       2017-05-22 10:31:28 +08:00   1
    论讲闭包的文章, 我只服这一个系列:深入理解 Javascript 原型和闭包(完结) http://www.cnblogs.com/wangfupeng1988/p/3977924.html


    这个是我看过讲的最透彻的了
    sensui7
        11
    sensui7  
       2017-05-22 14:00:26 +08:00
    @Biwood 可以引入'context'这个概念解释 this, 但是你就必须解释 context 是什么, 否则就更让人迷惑, 但是这么做的话, 你又需要记住 context 的不同情况( 函数的 context, 方法的 context, 构造函数的 context), 这样与直接记住 this 的取值有什么不同呢?

    所以, 像 You don't know JS 里的解释 this 方法虽然有启发性, 但对实践中对 this 的使用其实并无多大帮助, 你还是需要记住不同情况下 this 的取值.
    我的看法是 You don't know JS 这本书适合有一定经验的人翻翻, 当作甜点, 对工程来讲, 它偏理论, 偏学术. 对理论来讲, 又太浅了, 又不够系统.
    Biwood
        12
    Biwood  
       2017-05-22 14:39:41 +08:00
    @sensui7 我没看过你说的那本书,纯粹基于自己的理解写的。Context 和执行环境,这些词语的意思如果都理解不了那么根本不用学什么 Javascript 了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     844 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 22:07 PVG 06:07 LAX 14:07 JFK 17:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86