假设我有一个对象构造函数和一个原型(prototype)方法,例如:
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
在我的代码的其他地方,我定义了一个 human 的实例:
let jeff = new Human('jeff');
最后我想将 jeff.sayName
作为回调传递给其他一些函数,比如(对于一个特别简单的例子)
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
当我在上面调用 callFunction(jeff.sayName)
时,上下文需要绑定(bind)到 jeff
本身,比如
调用函数(jeff.sayName.bind(jeff))
。但这很笨拙,我不想每次使用此方法作为回调时都担心这种逻辑。
另一种方法是将 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 我想要一种将对象的原型(prototype)方法绑定(bind)到继承它的任何对象的方法,而不必在每次将该方法作为参数传递或每次定义新对象时都这样做。对不起,如果这没有什么意义。谢谢!
最佳答案
由于词法环境、作用域解析、原型(prototype)继承和环境记录在 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
对象上。它存在于函数对象的原型(prototype)中,当您执行对象属性查找时,JavaScript 引擎搜索原型(prototype)链以找到该函数。
您很可能会得到您所要求的行为,但不会受到您所设置的约束。例如,如果函数不必存在于原型(prototype)链上,而是可以存在于实例上(请记住,这会为每个实例创建一个新的函数对象,因此会增加成本),您可以定义函数在构造函数中,然后使用不会被覆盖的标识符存储对正确 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
的值是多少。
关于javascript - 我可以将构造函数的原型(prototype)方法绑定(bind)到构造的实例,同时保持关注点分离吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47897716/