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

2017-05-21 23:17:22 +08:00
 cheroky

《 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 跟闭包搞晕了。。。

2920 次点击
所在节点    JavaScript
12 条回复
ferrum
2017-05-21 23:50:13 +08:00
唉哟好长,后面的没看,就说第二个函数。

第二个函数`object2`,里面的`this`就是指向`window`,当你`this.name = "my"`时,你实际上是在`window`变量上定义了一个`name`属性。
wangjie
2017-05-22 00:03:03 +08:00
lijsh
2017-05-22 00:18:33 +08:00
第一个例子和第四个例子有可比性,因为都是在 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
2017-05-22 00:19:43 +08:00
更正:“……自动指向全局,这就是第四个例子里最后一个 console.log(this.name)输出‘ The Window ’” 的原因。
seki
2017-05-22 00:24:41 +08:00
this 指向的是函数的调用者
SuperMild
2017-05-22 00:30:42 +08:00
this 和闭包是两套东西,变量受闭包影响,但 this 不受闭包影响。总之,this 和闭包不要混在一起看,会很混乱。
SuperMild
2017-05-22 00:32:35 +08:00
单独理解 this 的规则就好,看 you don't know is
sensui7
2017-05-22 01:32:33 +08:00
可以放弃 望远镜那本书了, 虽然经典, 已经落伍了. 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
2017-05-22 09:23:52 +08:00
楼上几个没说到点上,关键词: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
2017-05-22 10:31:28 +08:00
论讲闭包的文章, 我只服这一个系列:深入理解 javascript 原型和闭包(完结) http://www.cnblogs.com/wangfupeng1988/p/3977924.html


这个是我看过讲的最透彻的了
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
2017-05-22 14:39:41 +08:00
@sensui7 我没看过你说的那本书,纯粹基于自己的理解写的。Context 和执行环境,这些词语的意思如果都理解不了那么根本不用学什么 JavaScript 了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/362841

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX