推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
cheroky

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

  •  
  •   cheroky · May 21, 2017 · 3795 views
    This topic created in 3303 days ago, the information mentioned may be changed or developed.

    《 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 replies    2017-05-22 14:39:41 +08:00
    bayallen
        1
    bayallen  
       May 21, 2017
    唉哟好长,后面的没看,就说第二个函数。

    第二个函数`object2`,里面的`this`就是指向`window`,当你`this.name = "my"`时,你实际上是在`window`变量上定义了一个`name`属性。
    lijsh
        3
    lijsh  
       May 22, 2017   ❤️ 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  
       May 22, 2017
    更正:“……自动指向全局,这就是第四个例子里最后一个 console.log(this.name)输出‘ The Window ’” 的原因。
    seki
        5
    seki  
       May 22, 2017
    this 指向的是函数的调用者
    SuperMild
        6
    SuperMild  
       May 22, 2017 via iPhone   ❤️ 1
    this 和闭包是两套东西,变量受闭包影响,但 this 不受闭包影响。总之,this 和闭包不要混在一起看,会很混乱。
    SuperMild
        7
    SuperMild  
       May 22, 2017 via iPhone
    单独理解 this 的规则就好,看 you don't know is
    sensui7
        8
    sensui7  
       May 22, 2017   ❤️ 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  
       May 22, 2017 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() // Context 是 window
    wensonsmith
        10
    wensonsmith  
       May 22, 2017   ❤️ 1
    论讲闭包的文章, 我只服这一个系列:深入理解 javascript 原型和闭包(完结) http://www.cnblogs.com/wangfupeng1988/p/3977924.html


    这个是我看过讲的最透彻的了
    sensui7
        11
    sensui7  
       May 22, 2017
    @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  
       May 22, 2017
    @sensui7 我没看过你说的那本书,纯粹基于自己的理解写的。Context 和执行环境,这些词语的意思如果都理解不了那么根本不用学什么 JavaScript 了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2858 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 55ms · UTC 08:21 · PVG 16:21 · LAX 01:21 · JFK 04:21
    ♥ Do have faith in what you're doing.