V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Angela2022
V2EX  ›  程序员

[javacript 的 this 指向问题, 高手请进]

  •  
  •   Angela2022 · 2022-11-19 10:21:53 +08:00 · 3416 次点击
    这是一个创建于 734 天前的主题,其中的信息可能已经有所发展或是发生改变。
    name = "哈哈"
    const pet1 = {
    name: 'Fluffy',
    getName1: () => this.name
    };
    console.log(pet1.getName1()); //哈哈

    function pet(name) {
    this.name = name;
    this.getName1 = () => this.name;
    }
    const cat = new pet('Fluffy');
    console.log(cat.getName1()); //Fluffy

    请问: 上面两个 console.log 都是打印相同的箭头函数, 为啥上面一个打印"哈哈", 下面一个打印 Fluffy ? 谢谢
    20 条回复    2022-11-21 13:51:07 +08:00
    looking0truth
        1
    looking0truth  
       2022-11-19 10:26:25 +08:00   ❤️ 2
    () => 的上下文在声明时所在的函数中
    下面的 this 是 pet ,上面的是 global
    isolcat
        2
    isolcat  
       2022-11-19 10:46:47 +08:00
    这里的 this 指向要根据你调用的环境来决定,第一个 pet1.getName1()就是指向的 global ,第二个 cat.getName1()在声明了参数'Fluffy'的情况下自然也就会指向所声明的函数
    你可以在 MDN 里搜索 this ,讲解的很详细
    anc95
        3
    anc95  
       2022-11-19 10:56:56 +08:00   ❤️ 2
    一楼说的对,二楼说了和没说一样
    sweetcola
        4
    sweetcola  
       2022-11-19 11:09:17 +08:00
    上面的 getName1 相当于只是一个函数变量,指向的是当前 context 的 this
    下面的 getName1 在函数中,new 之后就相当于在一个闭包里,context 不会随你在哪里调用而改变
    hahamy
        5
    hahamy  
       2022-11-19 11:26:00 +08:00
    箭头函数的 this 和调用无关,定义的位置在哪,this 就指向哪
    我简单粗暴的理解是,看结束的分号 ; 在哪,this 就指向分号位置的对象
    weiwoxinyou
        6
    weiwoxinyou  
       2022-11-19 11:43:29 +08:00
    ()=>{}中的 this 自动指向上一层
    rabbbit
        7
    rabbbit  
       2022-11-19 12:44:52 +08:00
    箭头函数没有 this
    zhaomeicheng
        8
    zhaomeicheng  
       2022-11-19 14:43:37 +08:00
    1. 箭头函数里的 this 是在箭头函数被定义那一刻决定的,且后续不会再变了。
    2. 箭头函数里的 this 是离它最近的外层普通函数的 this ,如果最外层是全局环境,那么即 window 。

    第一个输出:
    箭头函数定义的那一刻,外层没有普通函数,那么 this 是 window 。
    第二个输出:
    箭头函数定义的那一刻,外层普通函数是 pet 函数,且 pet 函数被调用是通过 new 操作符,所以 pet 函数的 this 是 cat 对象,即箭头函数的 this 是 cat 。
    lisongeee
        9
    lisongeee  
       2022-11-19 16:38:36 +08:00
    普通函数的 this 像是一个关键字语法糖,从 ast 的角度看,当这个函数被以 MemberExpression 被调用时,函数内的 this 是 Identifier
    箭头函数的 this 像是一个 const 变量语法糖,当箭头函数被声明时,额外在当前作用域声明了一个 <const>_this ,并将
    这个 _this 永久作为箭头函数内的 this

    ```js
    function Pet(name) {
    this.name = name;
    const _this = this;
    this.getName1 = () => _this .name;
    }
    ```
    QGabriel
        10
    QGabriel  
       2022-11-19 16:53:52 +08:00
    1. 箭头函数的 thsi 是上层的 this;
    console.log(pet1.getName1()) 相当于 window.pet1.getName1(); pet1 的 this 是 window

    2. new 方法 会在函数内隐式的声明一个 this 变量 值为空对象; let this = {}
    function pet('Fluffy') {
    this.name ='Fluffy';
    this.getName1 = () => this.name;
    }
    dcsuibian
        11
    dcsuibian  
       2022-11-19 17:02:46 +08:00
    一般的函数,都有一个隐藏的 this 参数。例如:
    function add ( a , b ){
    return a+b
    }
    这个函数的完整形式,你可以想象成:
    function add ( this, a , b ){
    return a+b
    }
    我习惯称这种形式为“函数的绝对表示”。

    如果你使用“对象.函数()”的方式调用,那么这个隐藏的 this 参数就会变成那个对象。比如 t.add(1,2),函数中收到的就是 add ( t, 1, 2)。

    但箭头函数,没有这个隐藏的 this 参数,也就是说
    let add=(a,b)=>{
    return a+b
    }
    它的绝对表示也都是这样。
    dcsuibian
        12
    dcsuibian  
       2022-11-19 17:05:42 +08:00
    用这种方法理解,那么你的函数:
    function pet(name) {
    this.name = name;
    this.getName1 = () => this.name;
    }
    其实可以看做:
    function pet( this, name) {
    this.name = name;
    this.getName1 = () => {
    return this.name;
    }
    }
    把 this 看成一个普通的参数,那么 this 其实就是使用了闭包机制。
    liuw666
        13
    liuw666  
       2022-11-19 18:03:32 +08:00 via iPhone
    写了一年多 react 都是函数组件,好像几乎没用过 this
    Justin13
        14
    Justin13  
       2022-11-19 19:23:33 +08:00 via Android
    箭头函数的 this 在声明时确定
    第一个指的是全局作用域,第二个指的是函数作用域
    而通常的 this,指向的是调用者
    karott7
        15
    karott7  
       2022-11-19 23:46:21 +08:00
    一楼答案正确且简洁
    xinleibird
        16
    xinleibird  
       2022-11-20 00:35:06 +08:00
    箭头函数的执行上下文不持有 ThisBinding ,采用的是 Lexical this (词法指的是执行上下文中的「环境」,理解为以作用域链替换 this 就成了)。其实这样越说越糊涂了……

    ```js
    const obj = {
    detail: "obj",
    getDetail() {
    console.log(this.detail);
    }
    }

    obj.getDetail(); // obj

    const getDetail = obj.getDetail;
    getDetail(); // undefined ,此时上下文是 global ,非严格模式,global 下 this 指向 window ,window 没有 detail
    ```

    ```js
    const obj = {
    detail: "obj",
    getDetail: () => {
    console.log(this.detail);
    },
    };

    obj.getDetail(); // undefined ,「对象字面量」 obj 不产生作用域,这个要注意。this 找上级作用域 window ,window 没有 detail 属性。
    ```
    1. 执行上下文除了 global 其余都是函数执行产生的。
    2. 你在函数中使用的 `this`,也就是执行上下文中的 `ThisBinding`,只与调用该函数的「对象」相关。
    3. 箭头函数是个特殊情况,它采用词法 this ,也就说,`this` 与上下文中「动态的」 ThisBinding ( obj 或 window ,`.`点号之前的……)无关,与「静态的」环境有关,要到环境(作用域链)中找。
    4. 而「对象字面量」`obj` 又不产生作用域(它顶多叫 namespace 名字空间)。由此会再向真正的作用域中找,外层的作用域就是 global ( window )。
    5. **简而言之**:箭头函数的词法 this 产生的效果是:把箭头函数上下文中的 this 绑定到 **『外层作用域』** 中。

    推荐到 https://muyiy.cn/blog/1/1.1.html 看看,博主写的很详细,跟着写写伪代码就清楚了。这样白嘴说其实越说越乱。
    DOLLOR
        17
    DOLLOR  
       2022-11-20 00:48:28 +08:00
    上面所有人都忘记提到的一点,非严格模式下,没有经过 let 、const 声明就直接赋值给一个变量名,它就成为全局变量,并且成为 window 下的同名属性。
    比如
    name = "哈哈"
    name 成了全局变量,并且也是 window.name 的值也是"哈哈"。如果在某个函数内 this 误指向了 window ,那么 this.name 的值也是"哈哈"。
    这种特性应该避免误用。
    AyaseEri
        18
    AyaseEri  
       2022-11-20 10:42:08 +08:00
    function 才能形成一个作用域吧,单纯字面量的对象并不能形成作用域。

    function Senpai(name) {
    this.name = name;
    return {
    getName1: () => this.name,
    getName2() { return this.name }
    }
    }

    这俩结果也是不一样的
    yaphets666
        19
    yaphets666  
       2022-11-21 11:27:43 +08:00
    就一句话,箭头函数的 this 指向和声明位置的 this 指向一致
    huangqihong
        20
    huangqihong  
       2022-11-21 13:51:07 +08:00
    看到高手就进来了,看到 this 指向问题就明白了,这无关“高手”的问题,
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2875 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:14 · PVG 19:14 · LAX 03:14 · JFK 06:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.