Могу ли я привязать методы прототипа конструктора к построенным экземплярам, оставив проблемы разделенными?
Скажем, у меня есть конструктор объекта и метод прототипа, например:
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))
. Но это неудобно, и я бы не стал беспокоиться об этой логике каждый раз, когда я использую этот метод в качестве обратного вызова.
Альтернативой было бы заменить 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 Мне нужен способ привязки метода прототипа объекта к любому наследуемому ему объекту, без необходимости делать это каждый раз, когда я передаю этот метод в качестве аргумента или каждый раз, когда я определяю новый объект. Извините, если это мало смысла. Спасибо!
Ответы
Ответ 1
Из-за того, что в 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());
Ответ 2
Расширяясь в ответ TinyGiant, вы можете использовать функцию стрелки, но если вы объедините ее с геттером, вы можете определить ее как метод прототипа и не беспокоиться о том, чтобы определить ваш обратный вызов как функцию стрелки, что может быть больше гибкий в зависимости от ваших потребностей. Вот так:
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)()
Ответ 3
Я полагаю, вы можете достичь этого
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()
});