萌新关于 js 箭头函数 this 的问题,头好晕 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
waibunleung
V2EX    Javascript

萌新关于 js 箭头函数 this 的问题,头好晕

  •  
  •   waibunleung 2019-02-28 16:53:19 +08:00 5414 次点击
    这是一个创建于 2424 天前的主题,其中的信息可能已经有所发展或是发生改变。

    萌新想问一个关于箭头函数 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 条附言    2019-02-28 17:41:53 +08:00
    问题问错了,是 obj.c.d();处为什么是 window 而不是 obj,之所以觉得是 obj 是因为搜索引擎的时候告诉我 箭头函数是没有 this 的,箭头函数里面的 this 永远指向父级上下文的 this
    41 条回复    2019-03-01 18:31:50 +08:00
    stillsilly
        1
    stillsilly  
       2019-02-28 16:57:55 +08:00
    obj.c.f() 打印的是 c
    wxsm
        2
    wxsm  
       2019-02-28 16:58:31 +08:00
    建议你 Google 一下箭头函数与普通函数的区别。
    stillsilly
        3
    stillsilly  
       2019-02-28 16:58:47 +08:00
    是 obj.c
    不是你说的 window,也不是 obj
    Exia
        4
    Exia  
       2019-02-28 16:59:55 +08:00
    obj.c.f() 应该是 c 吧
    dmjob2015222
        5
    dmjob2015222  
       2019-02-28 17:00:34 +08:00
    貌似是打印 obj.c 吧,箭头就是一个语法,看看介绍就明白了
    /div>
    roscoecheung1993
        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();
    roscoecheung1993
        7
    roscoecheung1993  
       2019-02-28 17:05:05 +08:00
    把这坨代码粘贴到 babel 的 playground 里面,你就懂了
    Wanex
        8
    Wanex  
       2019-02-28 17:07:03 +08:00
    楼上正解,c 是普通函数,谁调用它 this 就是谁,所以打印的是 c
    而箭头函数中的 this 始终指向自身外的第一个 this,也就是始终等于调用它的函数的 this
    Wanex
        9
    Wanex  
       2019-02-28 17:08:16 +08:00
    @Mexion 打错了,f 是普通函数,谁调用它 this 就是谁,所以打印的是 c
    myl0204
        10
    myl0204  
       2019-02-28 17:10:22 +08:00
    问题:obj.c.d();处打印出来的为什么是 window 对象而不是 obj 对象 ?
    binux
        11
    binux  
       2019-02-28 17:14:37 +08:00 via Android
    你想问的是 obj.c.d() 吧
    so1n
        12
    so1n  
       2019-02-28 17:18:27 +08:00
    rabbbit
        13
    rabbbit  
       2019-02-28 17:18:43 +08:00
    @myl0204
    1 this 是 function 的关键字,而箭头函数没有这个关键字
    2 关键字其实本质上就是函数作用域里的一个变量

    因为箭头函数里没有 this, 所以只能向上一层作用域里去找这个变量, 也就是 windows 了
    Chingim
        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 对象
    waibunleung
        15
    waibunleung  
    OP
       2019-02-28 17:39:06 +08:00
    @wxsm 这种东西我没 google 过我是不会上来问的,建议你下次不要提这种建议
    waibunleung
        16
    waibunleung  
    OP
       2019-02-28 17:39:42 +08:00
    @binux 对的对的
    dmjob2015222
        17
    dmjob2015222  
       2019-02-28 18:00:15 +08:00
    @waibunleung 你这 google 能力不行啊,这种问题 google 不出来???
    almost00
        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
    a4854857
        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
    AV1
        20
    AV1  
       2019-02-28 19:15:14 +08:00 via iPhone
    箭头函数并没有 this,如果你在箭头函数里写 this,实际上这个 this 属于它外层的普通函数,而不属于这个箭头函数。
    SilentDepth
        21
    SilentDepth  
       2019-02-28 19:48:41 +08:00
    Lexical this,是说这段代码的在文法(源码)所在位置是什么 this 就是什么 this。它不是没有 this,只是无法手动 bind。
    loy6491
        22
    loy6491  
       2019-02-28 20:09:21 +08:00 via iPhone   1
    父级指的是父级函数,不是父级对象。d 那个函数的外层没有其他函数了,直接到顶层就完事了
    waibunleung
        23
    waibunleung  
    OP
       2019-02-28 21:03:13 +08:00
    @dmjob2015222 你来你来,我发现来这里的有一部分回复不将焦点集中在问题上面,而是关注别的问题,解释一下又能怎样,我也不至于是伸手党啊,每个回复我都有好好研究,我连 MDN 都翻了,你跟我说这些对我完全没有意义,以前这种都是不回的,可是见多了真的忍不住....就像是我语气重了一点,依然跟你说多多担待一样,其实也没差~
    auroraccc
        24
    auroraccc  
       2019-02-28 21:17:29 +08:00
    你要理解对象本身是没有 this 的,箭头函数不会创建自己的 this, 它只会从自己的作用域链的上一层继承 this。那执行 obj.c.d()的时候,由于 c 和 obj 都没有 this,再沿着作用域链往上,console 出来的 this 就是 windows 了
    waibunleung
        25
    waibunleung  
    OP
       2019-02-28 21:17:54 +08:00
    @loy6491 听你这么说,我将代码转成 es5 试了一下,这样是能解释通的,暂时结案吧。欢迎反驳这个回复~
    waibunleung
        26
    waibunleung  
    OP
       2019-02-28 21:19:12 +08:00
    @auroraccc 你的解释跟 @loy6491 差不多,我大概理解了,感谢
    auroraccc
        27
    auroraccc  
       2019-02-28 21:21:47 +08:00
    打错,window
    waibunleung
        28
    waibunleung  
    OP
       2019-02-28 21:23:25 +08:00
    @auroraccc 就喜欢你这种严谨的小机灵鬼
    autoxbc
        29
    autoxbc  
       2019-02-28 21:46:26 +08:00
    注意箭头函数中 this 的上溯,不是沿着作用域链,不是函数调用链,不是成员访问链,是执行上下文
    waibunleung
        30
    waibunleung  
    OP
       2019-02-28 21:52:50 +08:00
    @autoxbc 我要怎么理解你这句话呢?能否详细一些...谢谢你的提点
    waibunleung
        31
    waibunleung  
    OP
       2019-02-28 21:55:27 +08:00
    @autoxbc 而且我翻 MDN 文档,里面有一句话:“箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this。"
    那这不是沿着作用域链来上溯吗....?
    rabbbit
        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 里根本就,没这些东西
    autoxbc
        33
    autoxbc  
       2019-02-28 23:05:04 +08:00
    @waibunleung #31 抱歉,是我想当然了,是作用域
    xieranmaya
        34
    xieranmaya  
       2019-02-28 23:08:49 +08:00
    看箭头函数里的 this 时,你就当在看 if 语句里的 this,这么说懂了吧
    posebear1990
        35
    posebear1990  
       2019-03-01 03:37:10 +08:00 via iPhone
    简单的说就是函数中 this 的值,如果显式绑定了的话(比如用 bind/call,或者箭头函数),就是绑定的值。否则没有显式绑定,那 this 等于调用对象。
    rodjl
        36
    rodjl  
       2019-03-01 08:45:37 +08:00 via iPhone
    https://github.com/mqyqingfeng/Blog/issues/7 this 这里面解释得挺好的
    a4854857
        37
    a4854857  
       2019-03-01 10:23:04 +08:00
    在查找楼主的问题过程中查漏补缺了不少东西...感谢楼主...
    amumu666
        38
    amumu666  
       2019-03-01 10:34:44 +08:00
    两句话,函数 this 指向运行时的作用域,箭头函数 this 指向定义时的作用域。
    wxsm
        39
    wxsm  
       2019-03-01 11:41:26 +08:00
    @waibunleung 绝大多数人在提问之前不会搜索,但是搜索确实可以解决这种问题。我相信我的回答在大部分时候是能提供帮助的。当然,这些题外话就没必要深入讨论了。
    waibunleung
        40
    waibunleung  
    OP
       2019-03-01 18:30:38 +08:00
    @autoxbc 我在网上找到了很多想当然的例子和文章,真心希望大家可以严谨求证,不然就真的很悲哀
    waibunleung
        41
    waibunleung  
    OP
       2019-03-01 18:31:50 +08:00
    @wxsm 你说的对,然而你的答案呢?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1530 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 16:39 PVG 00:39 LAX 09:39 JFK 12:39
    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