Я работаю над кодом JavaScript, который будет использоваться для создания конструкторов для «классов» (в частности, «Просмотр моделей») для нашего программного обеспечения на уровне предприятия. Одна из вещей, которые я делаю, - это создание шаблона проектирования с использованием кода, в котором разработчик будет явно определять, какие функции они хотят открыть экземпляром класса, а код добавит их в конструктор конструктора prototype
, так как против свойств каждого экземпляра класса. Это, конечно, имеет то преимущество, что только один экземпляр каждой из этих функций для каждого типа, в отличие от экземпляра для каждого экземпляра.Использование bind для принудительного использования функции прототипа
Here's a CodePen of most of my examples.
Проблема заключается в том, что при определенных условиях, я имею дело с binding loss вопросов. Например, с помощью этого конструктора:
function Foo(myName) {
this.firstName = myName;
}
Foo.prototype.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
... это будет работать:
var sam = new Foo("Sam");
// Alerts "Hello, Denny. I am Sam."
sam.greet("Denny");
... но это не будет:
var sad = new Foo("Sad");
// This changes the context of greet. :(
var sadGreet = sad.greet;
// Alerts "Hello, Denny. I am undefined."
sadGreet("Denny");
Это происходит потому, что когда мы делаем var sadGreet = sad.greet
мы меняем контекст функции greet
на window
, поэтому this.firstName
не существует при вызове sadGreet("Denny")
.
Таким образом, решение, которое я придумал было перезаписать прототип со свойством, который вызывает этот прототип, окружив его Function.prototype.bind()
:
function Bar(myName) {
this.firstName = myName;
// Here's where the magic happens.
this.greet = Bar.prototype.greet.bind(this);
}
Bar.prototype.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
var happy = new Bar("Happy");
// Since each instance of Bar overwrites the context for greet, this will work. :)
var happyGreet = happy.greet;
// Alerts "Hello, Denny. I am Happy."
happyGreet("Denny");
Мой вопрос заключается в следующем: Я предполагаю, что Bar
является не так эффективны, как Foo
, но делает это полностью аннулирование какой-либо выгоды от объявления greet
как метода prototype
? Под обложками он просто дублирует greet
как собственность, во всяком случае, или мой призыв к bind
просто добавляет «обертку» для Bar.prototype.greet
? Другими словами, действительно ли это то же самое, что и приведенное выше определение для Bar?
function Bar(myName) {
this.firstName = myName;
// Here's where the magic happens.
this.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
}
Бонусные баллы, если вы не можете ответить только на вопрос, но скажите мне, как его проверить!
Вопросы об эффективности, как правило, жестко для SO, потому что трудно ответить окончательно. Тем не менее, моя основная реакция заключается в том, что я считаю «happyGreet (...)» вообще ошибкой. Если функция находится в экземпляре, вы, вероятно, не должны назначать ее переменной, если, если вы это делаете, вы должны ".свяжите его там в месте назначения или сделайте 'happyGreet.call (happy,« Denny »)' – loganfsmyth
@loganfsmyth Спасибо за ваш ответ, и я согласен. К сожалению, это лишь один из нескольких возможных примеров того, как может произойти «потеря связи», и я не обязательно контролирую каждую реализацию этих конструкторов. – Grinn
Контекст выполнения функции включает в себя параметр * this *, который устанавливается ** по тому, как вызывается функция **, или используя * bind *. Если вы измените способ вызова функции, вы, вероятно, измените ее * на этом *. Или нет. – RobG