假设我有一个对象构造函数和一个原型方法,比如:
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
在我的代码中,我已经定义了一个人类实例:
let jeff = new Human('jeff');
最后我希望将jeff.sayName
作为回调传递给其他一些函数,例如(对于一个特别简单的例子)
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
当我在上面调用callFunction(jeff.sayName)
时,上下文需要绑定到jeff
本身,就像
callFunction(jeff.sayName.bind(jeff))
。但这很笨重,而且每次我使用这种方法作为回调时,我都不必担心这种逻辑。
另一种方法是用{/ p>之类的东西替换Human.prototype.sayName
Human.prototype.createSayName = function(context){
return function() {
console.log(context.name);
};
};
然后用
定义函数jeff.sayName = jeff.createSayName(jeff)
但这有点尴尬,我希望jeff
对Human.prototype
继承的方法保持不可知。
理想情况下,我想在Human.prototype上处理这个逻辑,比如
Human.prototype.sayName.bind(WhateverObjectHoldsThisMethod)
但我不知道javascript有办法做到这一点。
TL; DR我想要一种将对象的原型方法绑定到任何对象继承它的方法,而不必每次将该方法作为参数传递或每次定义新对象时都这样做。对不起,如果这没什么意义。谢谢!
答案 0 :(得分:3)
由于词法环境,范围解析,原型继承和环境记录在JavaScript中的工作方式,如果不修改调用回调函数的函数,就无法提出要求。
但是,你可以 - 而不是传递Human#sayName
引用作为回调 - 使用箭头函数,而该函数又调用你想要调用的Human#sayName
引用。
它并不完美,但它简单,干净,易读。
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(_ => jeff.sayName());

为了更好地理解我之前引用的那些花哨的单词,以及它们如何在JavaScript中工作,我建议阅读ECMAScript 2017 Language Specification的第8.1节。第8.1.1.3小节具有您正在寻找的具体信息,但到目前为止的其余部分对于理解该小节是必要的。
基本上,当您将Human#sayName
传递给callFunction
时,您已将引用传递给原始sayName
函数,因此您可能会这样做: (原谅双关语)
function callFunction(callback) {
callback();
}
callFunction(function(){
console.log('my name' + this.name);
});
函数的内容在执行之前不会被评估,这意味着在执行时,this
的值已经改变。要添加到崩溃中,原始函数不知道您请求它通过哪个实例。它实际上从未存在于jeff
对象上。它存在于函数对象的原型中,当您执行对象属性查找时,JavaScript引擎会搜索原型链以查找该函数。
你很可能得到你所要求的行为,但不会受到你所规定的限制。例如,如果函数不必存在于原型链上,而是可以存在于实例上(请记住,这会为每个实例创建一个新的函数对象,因此会增加成本),您可以定义函数在构造函数中,然后使用不会被覆盖的标识符存储对正确this
的引用:
function Human(name) {
const _this = this;
this.name = name;
this.sayName = function(){
console.log('my name' + _this.name);
};
}
let jeff = new Human('jeff');
function callFunction(callback) {
const _this = { name: 'hello' }; // does not affect output
callback();
callback.call(_this); // does not affect output
}
callFunction(jeff.sayName);

这将是一个更安全的选项,因为您知道_this
将始终引用您希望它在构造函数的上下文中引用的对象,该函数对象中定义的所有函数对象将继承其父作用域的标识符,这些标识符不会受到调用上下文的影响。
或者,你可以更进一步,而不是完全依赖this
的价值:
function Human(name) {
const sayName = function(){
console.log('my name' + name);
};
Object.assign(this, { name, sayName });
}
let jeff = new Human('jeff');
function callFunction(callback) {
const name = 'hello'; // does not affect output
callback();
callback.call({ name: 'world' }); // does not affect output
}
callFunction(jeff.sayName);

这有以下优点:
this
的价值。答案 1 :(得分:1)
扩展TinyGiant的答案,你可以使用箭头功能,但是如果你把它与一个getter结合起来,你可以将它定义为原型的方法,而不是将你的回调定义为箭头函数,这可能更多灵活取决于您的需求。像这样:
function Human(name) {
this.name = name;
}
Object.defineProperty(Human.prototype, "sayName", {
get: function() {
return () => {
console.log("my name is", this.name);
}
}
});
function callfunction(callback) {
callback();
}
let jeff = new Human('jeff');
callfunction(jeff.sayName);
// just to show it works even as a regular function
jeff.sayName();
// in fact it overrides every context you bind
jeff.sayName.bind(window)()
答案 2 :(得分:-1)
我想你可能想要实现这个
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(function() {
jeff.sayName()
});

另一个猜测,一个绑定到实例的原型,它有效,但有反模式
function Human(name) {
this.name = name;
}
const jeff = new Human('jeff');
Human.prototype.sayName = function() {
console.log('my name' + jeff.name);
};
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);

另一个猜测,选举
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
Human.prototype.reflectName = function(item) {
this.sayName = () => item.sayName()
};
const jeff = new Human('jeff');
const tod = new Human('tod');
tod.reflectName(jeff)
tod.sayName()