2014-10-04 6 views
9

Оба кодовых блока ниже работают, в контексте и кажутся полностью функционально эквивалентными. Я понимаю js prototypes достаточно хорошо, поэтому я не спрашиваю о них как таковых (если только не является).viewmodel .prototype .функция vs self .функция в viewmodel?

Скорее, сравнивая два простых способа, чтобы положить метод на модели представления, как показано ниже, есть какие-либо последствия/различия для Knockout, например, время связывания?

определяют ([ "Нокаут", "текст ./ home.html!"], Функция (ко, homeTemplate) {// < - An AMD Module

function HomeViewModel(route) { 
      var self = this; 
      self.message = ko.observable('Snacks!'); 

      self.eatSomething = function() { 
        self.message('Yum, a viewmodel snack.'); 
      }; 
    } 
    return { viewModel: HomeViewModel, template: homeTemplate }; 
}); 

против добавления Способ по прототипу:

определяют ([ "нокаут", "! текст ./ home.html"], функция (ко, homeTemplate) {

function HomeViewModel(route) { 
      this.message = ko.observable('Snacks!'); 
    }; 

    HomeViewModel.prototype.eatSomething = function() { 
      this.message('Yum, the same viewmodel snack, only different?'); 
    }; 
    return { viewModel: HomeViewModel, template: homeTemplate }; 

});

(код простые моды из Yeoman's выхода подмостей через Knockout generator. Он создал код котла пластины для knockout component, довольно недавно (KO 3.2) и очень приветствуется. Хороший компонент объяснитель KO является here.)

ответ

11

в первом примере, так как функция использует self (который установлен в отношении нового экземпляра), а не this, независимо от того, как эта функция называется/ограничена, она не всегда правильно установить свой собственный message наблюдаемым ,

Во втором примере, когда привязка обычно к функции, например data-bind="click: eatSomething", вы получите тот же результат. Нокаут вызывает функцию со значением this, равным текущим данным.

Если у вас был сценарий, в котором вам нужно было вызвать функцию из другого контекста (возможно, ваша модель представления имеет дочерний объект, который вы используете with или шаблон против). то вы можете использовать привязку, такую ​​как data-bind="click: $parent.eatSomething". KO все равно вызовет функцию с this, равным текущим данным (что не будет $parent), поэтому у вас возникнет проблема.

Одно из преимуществ ввода функции на прототипе, хотя, является то, что если вы создали много примеров HomeViewModel они все одни и те же функции eatSomething через их прототип, а не каждый экземпляр, получая свою собственную копию функции eatSomething. Это может не беспокоить ваш сценарий, поскольку у вас может быть только один HomeViewModel.

Вы можете убедиться, что контекст правильный, назвав его как: data-bind="click: $parent.eatSomething.bind($parent). Используя этот вызов, создаст новую функцию-обертку, которая вызывает оригинал с соответствующим контекстом (значение this). Кроме того, вы можете связать его в модели просмотра, а также сохранить очиститель привязки. В любом случае, вы теряете часть значения, помещающего его в прототип, поскольку вы каждый раз создаете функции-обертки для каждого экземпляра. «Кишки» функции будут существовать только один раз на прототипе, хотя по крайней мере.

Я использую прототипы в своем коде, но нет сомнений в том, что использование техники self (или что-то вроде шаблона модуля отображения) может уменьшить вашу озабоченность значением this.

+0

Полезное разъяснение - что вы подразумеваете под термином «раскрывающий модуль» **? Кстати, я просто наткнулся на ваших [Нокаутов AMD Helpers] (https://github.com/rniemeyer/knockout-amd-helpers) - выглядит чрезвычайно полезно - особенно, как модули, содержащие свои собственные шаблоны. Так что спасибо за это! –

+0

Существует несколько ссылок, описывающих шаблон раскрывающего модуля, вот один из них: http://weblogs.asp.net/dwahlin/techniques-strategies-and-patterns-for-structuring-javascript-code-revealing-module- шаблон. В принципе, вы определяете любые методы, которые хотите внутренне, и можете напрямую ссылаться на переменные. Затем вы возвращаете публичный «API» из модуля с помощью методов, которые вы хотите открыть, с любыми именами, с которыми вы хотите их разоблачить. Надеюсь, это поможет! –

+1

@RPNiemeyer - ты не написал блог по этому точному вопросу? Я думал, что вспомнил, что читал это в прошлом и занимался поиском в Интернете, и вот где я оказался – user210757