以下代码(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
?
答案 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
引用的四个规则。
new
关键字调用了当前函数Function#call
或Function#apply
调用了该函数。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