【问题标题】:Why does 'this' result as 'Undefined' in method [javascript]为什么在方法 [javascript] 中“this”会导致“未定义”
【发布时间】:2020-03-22 13:37:22
【问题描述】:

我正在研究这个内部对象方法的行为,但我卡在了一个输出上。

这是代码。

'use strict';

let obj, method;

obj = {
  go() { alert(this); }
};

obj.go();               // (1) [object Object]

(obj.go)();             // (2) [object Object]     QUESTION 2

(method = obj.go)();    // (3) undefined

(obj.go || obj.stop)(); // (4) undefined     ------> Doubt  <-------------------

那么如果第四个在逻辑上等价于第二个,为什么逻辑OR会导致上下文丢失?

第二部分

如果我错了,请纠正我。

  1. 通过函数声明/表达式调用/调用它的方式发生此评估。

  2. 在箭头函数内部,this 始终引用其封闭的父级。 [词法范围]

【问题讨论】:

    标签: javascript object methods ecmascript-6 this


    【解决方案1】:

    在情况 2 中,括号不会改变 () 左侧的函数引用值来自对象属性引用的事实。因此,函数调用的发生方式与案例 1 完全相同,对象引用绑定到 this

    然而,在情况 4 中,这些括号内的 || 评估会导致该关系丢失;剩下的就是没有任何相关对象的函数引用。那是因为||的逻辑并不关心函数引用来自对象属性查找这一事实,所以它的结果值只是“裸”的函数引用。

    关于您的后续问题,这两个断言的措辞都不正确。 this 的值确实取决于函数的调用方式,但这与函数的来源或声明方式无关。在箭头函数内部,this 的值不是对其词法父项的引用,它与词法父项中this 的值相同。

    【讨论】:

    • 我会说这种行为有点令人惊讶,尽管我认为如果它的工作方式不同,将会在运行时引入大量的复杂性。
    • (obj.go || obj.stop)(); -> 评估是如何发生的?...首先是点运算符,然后是或运算符,obj.go 是真的..因此它简化为 obj.go()...我知道我的断言在某个地方是错误的..请详细说明评估进程
    • 评估obj.go 表达式,并检查其值是否“真实”。是的,所以|| 表达式的求值停止并且整体值是函数引用。如果您阅读规范(不幸的是,这既乏味又困难),关键区别在于获取值的 reference 与实际值本身之间的区别。这相当神秘。更实际的做法是简单地接受函数值对象属性和对象之间的关系在任何表达式求值中都会丢失。
    • 所以在任何表达式评估中,参考值都会丢失..对吗?
    • @tedd 对象 - 函数关系丢失,是的,除非表达式是 only object.propertyName
    【解决方案2】:

    @Pointy 已经回答了您的问题。只是为了好玩:知道你现在知道什么,你可以让你的 obj.go 方法在它自己的范围内运行,包装在一个箭头函数表达式中:

    let obj, method, otherMethod, m2;
    
    obj = {
      foo: `obj.foo here, saying: done`,
      go(txt = ``) { console.log(`obj.go here, called as: ${txt} => ${this.foo}`); }
    };
    (txt => obj.go(txt))(`(txt => obj.go(txt))([...])`);
    (method = txt => obj.go(txt))(`(method = txt => obj.go(txt))([...])`);
    (obj.go && 
      (txt => obj.go(txt)) || 
      obj.stop)(`(obj.go && txt => obj.go(txt) || obj.stop)([...])`);
    
    // or use a wrapper (factory function)
    const wrap = (...[obj, method, txtArg]) => () => obj[method](txtArg);
    (otherMethod = wrap(obj, `go`, `(otherMethod = wrap(obj, \`go\`, \`[...]\`))()`))();
    
    // or make `go` a getter and that getter a factory function
    let otherObj = {
      foo: `and hithere, here's otherObj.foo`,
      get go() { return txt => 
        console.log( `otherObj.go here, called as: ${txt} => ${this.foo}` ); }
    };
    
    (m2 = otherObj.go)(`(m2 = otherObj.go)([...])`);
    .as-console-wrapper { top: 0; max-height: 100% !important; }

    【讨论】:

      【解决方案3】:

      其实#的3和4返回[object Window]

      见 cmets:

      let obj, method;
      
      obj = {
        go() { alert(this); }
      };
      
      obj.go();               // [object Object] represents obj
      
      (obj.go)();             // [object Object] represents obj
      
      (method = obj.go)();    // [object Window] because the go method is not running in the context of obj
      
      (obj.go || obj.stop)(); //  Same as above

      【讨论】:

      • 我已经使用了'use strict',我现在已经将它添加到代码中
      猜你喜欢
      • 2016-07-18
      • 2011-04-30
      • 2014-01-31
      • 1970-01-01
      • 2021-09-01
      • 2018-08-17
      相关资源
      最近更新 更多