为什么在通过逻辑运算符调用的函数中未定义“ this”?

时间:2019-11-05 21:27:19

标签: javascript

以下代码(codepen)不起作用。

"use strict"; //without strict "this" works, but it refers to window object

let person = {
  name : "Shimon",
  logName : function(){
    //console.log("test") //this works
    console.log(this.name); //doesn't work
  }
};

//person.logName(); //works
(false || person.logName)(); //doesn't work. Uncaught TypeError: Cannot read property 'name' of undefined

我想了解为什么。
当我打电话给(false || person.logName)();时,我想打电话给person.logName(),它确实被调用了。
那么,为什么不能在此方法内使用this

4 个答案:

答案 0 :(得分:2)

这就是Javascript语义的行为方式。除非您从对象调用该方法,否则该方法将无法附加到this上。

您的示例:

(false || person.logName)();

可以改写为:

var func = person.logName;
func();

在这里您可以直观地看到有一个中间步骤,其中logName()person分离。这具有删除this上下文的副作用。


有多种方法可以在“分离”功能上强制使用this上下文。其中之一就是Function.prototype.bind(),它可以将this绑定到任何功能。

(false || person.logName.bind(person))();

此处创建了一个新功能,其中person绑定为this,以实现所需的行为。另外,您可以使用Function.prototype.call()来避免创建新函数。

(false || person.logName).call(person);

这可以在您想像的用例中使用,但是它可能不适合您的实际用例,因为当您“分离”的功能不是从中分离时,您将需要传递不同的对象作为this参数。同一对象。

答案 1 :(得分:2)

JavaScript引擎确定this引用的四个规则。

  1. 新界 :使用new关键字调用了当前函数
  2. 显式绑定 :使用Function#callFunction#apply调用了该函数。
  3. 隐式绑定 :函数是否直接在其拥有的对象上?
  4. 默认 :如果处于严格模式下,undefined否则为global

在您的情况下,person.logName()属于第三类,因此将this引用设置为person的值。
但是在另一种情况下,行(false || person.logName)()等效于var x = false || person.logName; x();。那是因为您使用表达式来获取函数,因此上下文丢失了。
因此,您需要使用person.logName()(false || person.logName).call(person)

这是一个更复杂的示例:

var actionMap = {
  0: function() {
    console.log(this === actionMap ? "actionMap" : "global");
  },
  1: function() {
    console.log(this === actionMap ? "actionMap" : "global");
  },
};

function other() {
  console.log(this === actionMap ? "actionMap" : "global");
}

actionMap[0](); // works
(actionMap[0])(); // works, brackets get ignored
(actionMap[0] || actionMap[1])(); // context is lost in the expression
(actionMap[2] || actionMap[1])(); // context is lost in the expression
(actionMap[2] || actionMap[1]).call(actionMap); // works, context is called explicitly

var boundOther = other.bind(actionMap);
(boundOther || actionMap[1])(); // function is bound

如您在本示例中看到的,即使两个函数都属于同一对象,上下文也会丢失。由于要调用的函数是由表达式派生的,因此不会立即在其拥有的对象上调用。

答案 2 :(得分:-1)

适用于实例化的类/函数。在您的情况下,您必须将对象视为静态对象,例如:

let person = {
  name : "Shimon",
  logName : function(){
    console.log(person.name);
  }
};

答案 3 :(得分:-1)

如果您想要这种行为,则可以使用类或原型继承

class Person {
  constructor(name) {
    this.name = name;
  }

  logName() {
    console.log(this.name);
  }
}

function person(name) {
  this.name = name;
}

person.prototype.logName = function() {
  console.log(this.name);
}
let shimon = new Person("Shimon");
shimon.logName()  // >> Shimon