《 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 跟闭包搞晕了。。。
1
ferrum 2017-05-21 23:50:13 +08:00
唉哟好长,后面的没看,就说第二个函数。
第二个函数`object2`,里面的`this`就是指向`window`,当你`this.name = "my"`时,你实际上是在`window`变量上定义了一个`name`属性。 |
2
wangjie 2017-05-22 00:03:03 +08:00 1
|
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 赋值,所以后面拿回来的自然也是这个值。 |
4
lijsh 2017-05-22 00:19:43 +08:00
更正:“……自动指向全局,这就是第四个例子里最后一个 console.log(this.name)输出‘ The Window ’” 的原因。
|
5
seki 2017-05-22 00:24:41 +08:00
this 指向的是函数的调用者
|
6
SuperMild 2017-05-22 00:30:42 +08:00 via iPhone 1
this 和闭包是两套东西,变量受闭包影响,但 this 不受闭包影响。总之,this 和闭包不要混在一起看,会很混乱。
|
7
SuperMild 2017-05-22 00:32:35 +08:00 via iPhone
单独理解 this 的规则就好,看 you don't know is
|
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 的取值问题. |
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() // Context 是 window |
10
wensonsmith 2017-05-22 10:31:28 +08:00 1
论讲闭包的文章, 我只服这一个系列:深入理解 javascript 原型和闭包(完结) http://www.cnblogs.com/wangfupeng1988/p/3977924.html
这个是我看过讲的最透彻的了 |
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 这本书适合有一定经验的人翻翻, 当作甜点, 对工程来讲, 它偏理论, 偏学术. 对理论来讲, 又太浅了, 又不够系统. |