萌新想问一个关于箭头函数 this 的问题,看了好多例子还是理解不了。
代码:
var obj = {
a : 12,
b : () => {console.log(this)},
c : {
d: () => {console.log(this)},
f: function(){console.log(this)}
},
e : function(){console.log(this)}
}
obj.b();
obj.c.d();
obj.c.f();
obj.e();
问题:obj.c.f();
处打印出来的为什么是 window
对象而不是 obj
对象 ?
1
stillsilly 2019-02-28 16:57:55 +08:00
obj.c.f() 打印的是 c
|
2
wxsm 2019-02-28 16:58:31 +08:00
建议你 Google 一下箭头函数与普通函数的区别。
|
3
stillsilly 2019-02-28 16:58:47 +08:00
是 obj.c
不是你说的 window,也不是 obj |
4
Exia 2019-02-28 16:59:55 +08:00
obj.c.f() 应该是 c 吧
|
5
dmjob2015222 2019-02-28 17:00:34 +08:00
貌似是打印 obj.c 吧,箭头就是一个语法,看看介绍就明白了
|
6
roscoecheung1993 2019-02-28 17:02:15 +08:00
obj.c.f() 打印的是 obj.c 啊...
var obj = { a : 12, b : () => {console.log(this)}, c : { d: () => {console.log(this)}, f: function(){console.log(this); return this;} }, e : function(){console.log(this)} } obj.b(); obj.c.d(); console.log(obj.c.f() === obj.c); obj.e(); |
7
roscoecheung1993 2019-02-28 17:05:05 +08:00
把这坨代码粘贴到 babel 的 playground 里面,你就懂了
|
8
Mexion 2019-02-28 17:07:03 +08:00
楼上正解,c 是普通函数,谁调用它 this 就是谁,所以打印的是 c
而箭头函数中的 this 始终指向自身外的第一个 this,也就是始终等于调用它的函数的 this |
10
myl0204 2019-02-28 17:10:22 +08:00
问题:obj.c.d();处打印出来的为什么是 window 对象而不是 obj 对象 ?
|
11
binux 2019-02-28 17:14:37 +08:00 via Android
你想问的是 obj.c.d() 吧
|
12
so1n 2019-02-28 17:18:27 +08:00
|
13
rabbbit 2019-02-28 17:18:43 +08:00
@myl0204
1 this 是 function 的关键字,而箭头函数没有这个关键字 2 关键字其实本质上就是函数作用域里的一个变量 因为箭头函数里没有 this, 所以只能向上一层作用域里去找这个变量, 也就是 windows 了 |
14
Chingim 2019-02-28 17:28:10 +08:00
@myl0204 因为 d() 函数的 this 指向它外层的 this
问题变成了 c 的 this 是什么? 如果 c 是一个函数, 那调用 obj.c() , c 里的 this 肯定是 obj. 但是 c 不是一个函数, 它没有 this, obj 也没有 this 所以 d() 的外层的 this 就是 window 对象 |
15
waibunleung OP @wxsm 这种东西我没 google 过我是不会上来问的,建议你下次不要提这种建议
|
16
waibunleung OP @binux 对的对的
|
17
dmjob2015222 2019-02-28 18:00:15 +08:00
@waibunleung 你这 google 能力不行啊,这种问题 google 不出来???
|
18
almost00 2019-02-28 18:45:59 +08:00
// 你可以拷贝代码 到 jsbin 点 com 运行下试试
// 你不知道 this 是因为 你不用 call // this 是 fn.call(this) 的 第一个参数 // 这是历史原因,js 作者创造 js 的一个需求就是 要求它像 java // 所以你会看到很多 java 的面向对象写法,但是如果你是一个 js 程序员 就不会那样用 // 比如 js 你声明数组 var arr = [ ] java 就会这样 var arr = new Array( ) // 比如 var o = {} java 就要 var o = new Object() // 默认当前环境是浏览器且没用 严格模式 function a(){console.log(this);} a(); // window // a() 等价于 a.call(undefined) 所以是 window a.call(1); // 1 var o = {}; a.call(o); // o var o2 = {}; o2.a = a; o2.a(); // o2 console.log('----------华丽的分割线----------') var b = ()=>{console.log(this);} b(); b.call(1); // ES6 的箭头函数干掉了 this 和 arguments 参数 // 所以就算你强行指定 this 也会指向外层的 this |
19
a4854857 2019-02-28 19:05:33 +08:00
this 指向的固定化,并不是因为箭头函数内部有绑定 this 的机制,实际原因是箭头函数根本没有自己的 this,导致内部的 this 就是外层代码块的 this。正是因为它没有 this,所以也就不能用作构造函数。
所以,箭头函数转成 ES5 的代码如下。 // ES6 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } // ES5 function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); } 上面代码中,转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有自己的 this,而是引用外层的 this。 http://es6.ruanyifeng.com/#docs/function#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0 |
20
DOLLOR 2019-02-28 19:15:14 +08:00 via iPhone
箭头函数并没有 this,如果你在箭头函数里写 this,实际上这个 this 属于它外层的普通函数,而不属于这个箭头函数。
|
21
SilentDepth 2019-02-28 19:48:41 +08:00
Lexical this,是说这段代码的在文法(源码)所在位置是什么 this 就是什么 this。它不是没有 this,只是无法手动 bind。
|
22
loy6491 2019-02-28 20:09:21 +08:00 via iPhone 1
父级指的是父级函数,不是父级对象。d 那个函数的外层没有其他函数了,直接到顶层就完事了
|
23
waibunleung OP @dmjob2015222 你来你来,我发现来这里的有一部分回复不将焦点集中在问题上面,而是关注别的问题,解释一下又能怎样,我也不至于是伸手党啊,每个回复我都有好好研究,我连 MDN 都翻了,你跟我说这些对我完全没有意义,以前这种都是不回的,可是见多了真的忍不住....就像是我语气重了一点,依然跟你说多多担待一样,其实也没差~
|
24
auroraccc 2019-02-28 21:17:29 +08:00
你要理解对象本身是没有 this 的,箭头函数不会创建自己的 this, 它只会从自己的作用域链的上一层继承 this。那执行 obj.c.d()的时候,由于 c 和 obj 都没有 this,再沿着作用域链往上,console 出来的 this 就是 windows 了
|
25
waibunleung OP @loy6491 听你这么说,我将代码转成 es5 试了一下,这样是能解释通的,暂时结案吧。欢迎反驳这个回复😯~
|
26
waibunleung OP |
27
auroraccc 2019-02-28 21:21:47 +08:00
打错,window
|
28
waibunleung OP @auroraccc 就喜欢你这种严谨的小机灵鬼
|
29
autoxbc 2019-02-28 21:46:26 +08:00
注意箭头函数中 this 的上溯,不是沿着作用域链,不是函数调用链,不是成员访问链,是执行上下文
|
30
waibunleung OP @autoxbc 我要怎么理解你这句话呢?能否详细一些...谢谢你的提点
|
31
waibunleung OP @autoxbc 而且我翻 MDN 文档,里面有一句话:“箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this。"
那这不是沿着作用域链来上溯吗....? |
32
rabbbit 2019-02-28 22:13:05 +08:00
暂时不要去抠作用域 执行上下文这些本来就容易混淆的东西,知道 this 在不同场合指向哪就行
每代 Es 标准都在变,不一定过一段时间又加了啥新东西 例如 Es3 的 scope chain(作用域),到 Es5 里就没这个东西了,取而代之的是 Declarative Environment Record(声明式环境记录) http://ecma-international.org/ecma-262/5.1/#sec-D 还有什么 AO/VO ,es5 里根本就,没这些东西 |
33
autoxbc 2019-02-28 23:05:04 +08:00
@waibunleung #31 抱歉,是我想当然了,是作用域
|
34
xieranmaya 2019-02-28 23:08:49 +08:00
看箭头函数里的 this 时,你就当在看 if 语句里的 this,这么说懂了吧
|
35
posebear1990 2019-03-01 03:37:10 +08:00 via iPhone
简单的说就是函数中 this 的值,如果显式绑定了的话(比如用 bind/call,或者箭头函数),就是绑定的值。否则没有显式绑定,那 this 等于调用对象。
|
36
rodjl 2019-03-01 08:45:37 +08:00 via iPhone
https://github.com/mqyqingfeng/Blog/issues/7 this 这里面解释得挺好的
|
37
a4854857 2019-03-01 10:23:04 +08:00
在查找楼主的问题过程中查漏补缺了不少东西...感谢楼主...
|
38
amumu666 2019-03-01 10:34:44 +08:00
两句话,函数 this 指向运行时的作用域,箭头函数 this 指向定义时的作用域。
|
39
wxsm 2019-03-01 11:41:26 +08:00
@waibunleung 绝大多数人在提问之前不会搜索,但是搜索确实可以解决这种问题。我相信我的回答在大部分时候是能提供帮助的。当然,这些题外话就没必要深入讨论了。
|
40
waibunleung OP @autoxbc 我在网上找到了很多想当然的例子和文章,真心希望大家可以严谨求证,不然就真的很悲哀
|
41
waibunleung OP @wxsm 你说的对,然而你的答案呢?
|