Подтвердить что ты не робот

Какое преимущество использования `var self = this` в моделях просмотра knockout.js

В почти всех примерах вида knockout.js моделируется строка var self = this, а затем все локальные переменные являются ссылками как self.variableName. В чем преимущество этого при использовании this.variableName?

4b9b3361

Ответ 1

Обычно основной причиной использования этого подхода является то, что текущий this доступен для подфункций или замыканий. Например:

var myObject = {
  param: 123,
  method: function(){
    alert( this.param );
  },
  method2: function(){
    setTimeout(function(){
      alert( this.param );
    },100);
  }
}

В приведенном выше вызове myObject.method вы получите правильное предупреждение 123. Однако вызов myObject.method2 даст вам undefined. Это связано с тем, что this внутри анонимной функции, используемой с setTimeout, не относится к myObject, в зависимости от интерпретатора JavaScript это указывает на разные вещи. Однако, если у вас есть:

method2: function(){
  var self = this;
  setTimeout(function(){
    alert( self.param );
  },100);
}

Это работает, потому что текущее состояние this — в правой точке; и всегда будет ссылаться на myObject для каждой области видимости, доступной для нее.

Проблема не ограничивается использованием setTimeout. В любой момент, когда у вас есть анонимные функции, подфункции или замыкания, этот трюк пригодится. Иногда люди используют self или that или что-то более подробное описание в зависимости от того, что представляет текущая ссылка.


вместо сохранения в качестве переменной

Существует альтернатива использованию self или любой другой переменной, чтобы "запомнить" состояние этого в любой конкретной точке, а именно "привязать" ваши анонимные или вспомогательные функции к определенному контексту. Многие современные интерпретаторы теперь поддерживают метод Function.prototype.bind, который можно использовать таким образом:

var method = function(){
  console.log(this);
};
var methodWithWindow = method.bind(window);
var methodWithDocument = method.bind(document);
var methodWithObject = method.bind({random:"object"});

Вызов каждого из связанных методов в свою очередь даст вам следующий вывод консоли:

Window
Document
Object {random:"object"}

Если вы хотите поддерживать старые браузеры, вы можете использовать polyfill, или если вы предпочитаете гораздо более простую реализацию, которая не беспокоится о привязке аргументов также. Основы выполнения кода привязки следующие:

!Function.prototype.bind && (Function.prototype.bind = function(context){
  var method = this;
  return function(){
    method.apply(context, arguments);
  }
})

Итак, как бы выглядел исходный пример с помощью bind?

method2: function(){
  setTimeout((function(){
    console.log(this); // `this` will be the same as the `this` passed to bind.
  }).bind(this),100);
}

Как вы можете видеть выше, после привязки возвращаемая функция (закрытие) сохраняет указанный контекст; поэтому он может быть передан туда, где вы хотите, и по-прежнему сохраняйте ссылку this на нужный объект. Это полезно в примере method2, потому что мы собираем метод вверх с нашим текущим контекстом и передаем его в setTimeout, который позже выполнит связанный метод (после того, как мы выйдем из текущего выполнения блока).

То же самое происходит при использовании self или любой другой переменной. Переменная будет записана в цепочке видимости функции и все равно будет доступна для доступа, когда функция в конечном итоге будет вызвана. Преимущество использования bind заключается в том, что вы можете легко переопределить контекст, если вы этого пожелаете, вам придется закодировать свои собственные специальные методы, чтобы сделать это, чтобы переопределить переменную self.

ПРЕДУПРЕЖДЕНИЕ: Стоит отметить, что при связывании функции возвращается новая функция. Это может привести к запутывающим ситуациям, если вы смешаете связанные функции с прослушивателями событий, а затем попытаетесь удалить слушателей, используя исходную функцию, а не связанную версию.

Кроме того, поскольку привязка возвращает новую функцию, если вы привязываете связанную функцию, вы фактически обертываете функцию в функцию, с другой функцией. Вы должны знать об этом, потому что это влияет на производительность и окажется более сложным для управления с точки зрения предотвращения утечек памяти. Мой предпочтительный подход к привязке заключается в использовании закрытий с их собственными методами деконструкции (т.е. Полагаться на себя, но убедитесь, что у вас есть методы, чтобы свести его к нулю), но это требует более продуманного мышления и не столь актуально в небольших проектах JS; или одно выкл. функции привязки — особенно если связанный метод никогда не попадает в какую-либо ссылку.


без self и bind?

Также стоит упомянуть, что иногда вы можете добиться того же результата без использования bind вообще, а вместо этого использовать apply — который должен быть изначально доступен во всем, что вы можете использовать. Основное различие заключается в том, что ничто не обернуто функцией, а вызов apply фактически выполняет функцию там, а затем с другим контекстом — первый аргумент передан для применения.

var externalMethod = function(){
  console.log(this); // will output myObject when called below
};

var myObject = {
  method2: function(){
    externalMethod.apply(this);
  }
};


Что такое this?

Чтобы подробнее рассказать об этом ответе на this — до того, как последние комментарии будут удалены. this будет ссылаться на одну из четырех вещей, в зависимости от того, как была вызвана функция, в которой вы используете ее внутри:

myObject.method()

Вышеуказанное будет иметь this of myObject, если только method не выполнило операцию .bind(context). В этом случае this будет любым последним связанным контекстом.

unattachedFunction()

Будет иметь this глобального контекста (обычно window в средах браузера), если только unattachedFunction не выполнила операцию .bind(context). В этом случае this будет любым последним связанным контекстом.

anyFunction.apply(otherObject)

или

anyFunction.call(otherObject)

Оба всегда будут иметь this из otherObject, потому что вызов таким образом переопределит любую привязку.

new myObject()

Будет иметь this, который ссылается на новый экземпляр myObject, это переопределит любую привязку.


Простой мысленный эксперимент

Учитывая все сказанное выше, что бы this было внутри referencedMethod?

var referencedMethod = myObject.method;
referencedMethod();

Правильно! это будет глобальный контекст. Вот почему, если вы хотите делиться методами с другими объектами или кодом и— но все же сохранить первоначального владельца как context — вам действительно нужно либо привязать, либо сохранить функцию в комплекте с ее объектом-владельцем, чтобы вы могли позвонить или применить.

Ответ 2

Self используется, чтобы убедиться, что исходный this поддерживается внутри объекта.

Это полезно при использовании обработчиков событий и т.д.

Вы можете прочитать об этом здесь

Первый ответ охватывает его в основном, также он показывает хорошую ссылку. Проверьте это.

Ответ 3

Используется для справочных целей. this под Javascript ведет себя иначе, чем на других языках. Для более подробной информации смотрите MDN Docs на этом