2014-12-30 3 views
3

Я работаю над кодом 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 + "."); 
    } 
} 

Бонусные баллы, если вы не можете ответить только на вопрос, но скажите мне, как его проверить!

+0

Вопросы об эффективности, как правило, жестко для SO, потому что трудно ответить окончательно. Тем не менее, моя основная реакция заключается в том, что я считаю «happyGreet (...)» вообще ошибкой. Если функция находится в экземпляре, вы, вероятно, не должны назначать ее переменной, если, если вы это делаете, вы должны ".свяжите его там в месте назначения или сделайте 'happyGreet.call (happy,« Denny »)' – loganfsmyth

+0

@loganfsmyth Спасибо за ваш ответ, и я согласен. К сожалению, это лишь один из нескольких возможных примеров того, как может произойти «потеря связи», и я не обязательно контролирую каждую реализацию этих конструкторов. – Grinn

+0

Контекст выполнения функции включает в себя параметр * this *, который устанавливается ** по тому, как вызывается функция **, или используя * bind *. Если вы измените способ вызова функции, вы, вероятно, измените ее * на этом *. Или нет. – RobG

ответ

1

Бар определенно менее эффективен, чем Foo, но не с точки зрения временной сложности. Вместо этого он менее эффективен с точки зрения потребления памяти, поскольку каждый экземпляр Bar теперь имеет объект UNIQUE и NEW 'greet' (функция 'bind' создает новый функциональный объект).

Рассматривая свой код, он на самом деле становится немного запутанным, даже если функция «приветствовать» на Bar.prototype. Вместо этого, это работает так:

function Bar(myName) { 
    this.firstName = myName; 
    this.greet = greet.bind(this); 
} 

var greet = function(yourName) { 
    alert("Hello, " + yourName + ". I am " + this.firstName + "."); 
}; 

var happy = new Bar("Happy"); 
var happyGreet = happy.greet; 
happyGreet("Denny"); 

Вы можете проверить, что функция «поздороваться» не идентична функции каждого экземпляра «поздороваться», просто пытаясь это:

console.log(greet === happyGreet); 
+0

В вашем примере не будет 'happy.greet' также быть UNIQUE и NEW' greet'? – Grinn

+0

Нет, happy.greet - это просто СПРАВОЧНИК к объекту функции 'greet', который принадлежит каждому экземпляру Bar. В принципе функция «var greet» - это одна функция, и тогда каждый экземпляр Bar создает новую функцию «приветствия», основанную на функции «var greet». – wmock

+0

Отредактировал мой ответ, чтобы показать, что приветствие - это не та же функция, что и happyGreet. Это также работает в предыдущем примере: happyGreet! == Bar.prototype.greet – wmock

Смежные вопросы