Является ли var self = this; плохой шаблон?

Мне нужно:

var self = this;

много в моих классах javascript. Хотя это обычно делается, это кажется немного неправильным. То, что я надеюсь найти в этом вопросе, - лучший способ справиться с этим, или что-то, чтобы убедить меня, что это все в порядке.

Это стандартный способ сохранить правильные привязки? Должен ли я стандартизировать использование "я" везде, если я явно не нуждаюсь в 'this'.

edit: Я точно знаю, зачем мне это нужно, мне просто интересно, считалось ли это немного злым и почему. Я также знаю, что встроенная функция javascript 'apply' позволяет явно определять область при вызове метода. Это лучше?

Ответ 1

Как говорили другие: эта "дополнительная переменная" - это (на некотором уровне) единственный способ узнать, что this является специальным выражением и, следовательно, не является переменной, не связан в контексте выполнения/закрытия.

Однако, я думаю, что вы спрашиваете (или я действительно хочу ответить):

Следует ли положить var self = this в начало каждого метода/конструктора?

Резюме

Пока я пробовал это один раз и имел тот же вопрос, я больше не использую этот подход. Теперь я резервирую конструкцию, когда мне нужен доступ в закрытии. Для меня это добавляет немного "эй, это то, чего я действительно хочу!" семантический код:

this -> this и self -> this (but really that) in a closure

Вопросы ala carte:

... Хотя это обычно делается, это кажется немного неправильным. То, что я надеюсь найти в этом вопросе, - лучший способ справиться с этим, или что-то, чтобы убедить меня, что это все в порядке.

Делайте то, что вам нравится. Не бойтесь попробовать один метод и вернуться позже (но, пожалуйста, старайтесь оставаться последовательными в каждом проекте: -)

Это стандартный способ сохранить правильные привязки? Должен ли я стандартизировать использование "я" везде, если я явно не нуждаюсь в 'this'.

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

.. если он считал немного злым и почему.

Зло - глупый субъективный термин (хотя иногда и забавное). Я никогда не говорил, что это зло, просто почему я не следую этому подходу. Некоторые люди говорят мне, что я "злой" за то, что не использовал полуколоны. Я говорю им, что они действительно должны придумать хорошие аргументы и/или изучить JavaScript лучше: -)

Я также знаю, что встроенная функция javascript 'apply' позволяет явно определять область при вызове метода. Это лучше?

Проблема с apply/call заключается в том, что вы должны использовать их в точке вызова функции. Это не поможет, если кто-то другой называет один из ваших методов, поскольку this может уже отключиться. Это наиболее полезно для выполнения таких действий, как обратные вызовы стиля jQuery, где this - элемент/элемент обратного вызова и т.д.

Как в стороне...

Мне нравится избегать "необходимости" на членах и, таким образом, в целом продвигать все функции-члены к свойствам, где приемник (this) просто "протекает", что обычно "как ожидалось".

Методы "private" в моем коде начинаются с "_", и если пользователь вызывает их, то на них. Это также работает лучше (требуется, действительно) при использовании прототипа подхода к созданию объекта. Однако Дуглас Крокфорд не согласен с этим моим подходом "private", и есть некоторые случаи, когда поисковая цепочка может помешать вам, введя неожиданный приемник:

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

Счастливое кодирование.

Ответ 2

Да, это стандартный способ.

Function.apply() и Function.call() могут помочь, но не всегда.

Рассмотрим следующее

function foo()
{
  var self = this;
  this.name = 'foo';

  setTimeout( function()
  {
    alert( "Hi from " + self.name );
  }, 1000 );       
}

new foo();

Если вы хотите сделать это, но избегайте использования переменной типа self и вместо этого используйте call() или apply()... ну... вы смотрите на нее и начинаете пытаться, но скоро поймете, что вы просто не могу. setTimeout() отвечает за вызов лямбда, что делает невозможным использование этих альтернативных стилей вызова. Вы все равно создадите некоторую промежуточную переменную для хранения ссылки на объект.

Ответ 3

Это стандартный способ сохранить правильные привязки?

Нет стандарта, в котором рассматриваются системы JavaScript и класса/экземпляра. Вам нужно будет выбрать, какую именно модель объекта вы предпочитаете. Здесь другая ссылка на задний план; заключение: нет никакого заключения.

Обычно сохранение копии var self= this; (*) в закрытии идет рука об руку с объектной моделью, построенной вокруг замыканий с экземплярами каждого экземпляра каждого метода. Это правильный способ делать вещи; бит менее эффективен, но, как правило, немного меньше, чем альтернатива, объектная модель, построенная вокруг прототипирования, с использованием this, apply() и ECMAScript Fifth Edition bind() для получения связанных методов.

Что можно было бы считать более "злым", когда у вас есть миш-мэш обоих стилей в одном коде. К сожалению, многие распространенные JS-коды делают это (потому что, пусть сталкиваются с этим, никто не понимает самородную объектную модель JavaScript).

(*: Я обычно использую that вместо self, вы можете использовать любое имя переменной, которое вам нравится, но self уже имеет несколько неясное и совершенно бессмысленное значение как член window, который указывает на само окно.)

Ответ 4

Просто наткнулся на этот вопрос, потому что мои коллеги пристрастились к себе/этим переменным, и я хотел понять, почему...

Я думаю, что есть лучший способ справиться с этим в настоящее время:

function () {}.bind(this);      // native
_.bind(function () {}, this);   // lodash
$.proxy(function () {}, this);  // jquery

Ответ 5

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

Это важное различие в javascript по сравнению со многими другими языками, в которых мы работаем. Я прихожу из .Net, поэтому этот тип вещи мне сначала казался странным.

Edit: Ах, хорошо, ты все это знаешь. (возможно, все еще полезно для кого-то другого.) Я добавлю, что Apply (и Call) больше используются для использования извне, предоставляя функции, вызываемой определенной областью, о которой вы уже знаете. Когда вы находитесь внутри функции, и вы собираетесь каскадировать дальше в закрытие, техника:

  var self = this;

является более подходящим способом (easy и clear) для привязки текущей области.

Ответ 6

Скорее всего, это делается как способ сохранить ссылку на this, когда область действия изменится (в случае закрытия). Я не знаю, что я считаю, что это плохая практика или образец сами по себе, нет. Подобные вещи вы часто встречаете с такими библиотеками, как jQuery и очень много работаете с AJAX.

Ответ 7

Я думаю, что есть аргумент, который нужно всегда включать var self = this в каждый метод: человеческие факторы.

Достаточно часто требовалось, чтобы у вас возникли проблемы с методами доступа к this и другим, используя self для этой же цели. Если вы перемещаете код от одного к другому, вы получаете кучу ошибок.

В то же время я ловлю себя, рассеянно пишу self.foo по привычке, когда мне не нужен, или добавил var self = this. Поэтому я думаю, что было бы разумно просто привыкнуть к тому, чтобы всегда включать его, нужно или не нужно.

Единственная проблема в том, что... this, self или that - все это уродливая оспа на вашем коде, и я ненавижу их всех. Поэтому я думаю, что лучше избегать использования делегированных методов там, где это возможно, чтобы вы могли использовать this, that или self подавляющее большинство времени и использовать .bind(this), если в противном случае вы могли бы обратиться к self/that. Очень редко, что использование делегатов на прототипе на самом деле собирается сэкономить вам сколько-нибудь значительную часть памяти.

Хорошим побочным эффектом такого подхода является то, что вам не нужно префикс всех ваших личных переменных _, поскольку они будут действительно частными, а общедоступные свойства будут вызываться ведущим this., что делает ваш код более читабельный.

Как сказал bobince, var that = this лучше, потому что он не теневое window.self. self = this звучит менее неудобно для меня, но иногда вы получаете путаные сообщения об ошибках, такие как property myMethod not found on global, потому что вы забыли строку self = this.

Ответ 8

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

Ответ 9

Это 6 лет спустя, и у меня есть кое-что, чтобы добавить себя:

bind() теперь достаточно распространен, чтобы его можно было использовать повсюду. Я часто использую его в качестве альтернативы. Иногда это становится яснее. Я все же иногда пользуюсь var self = this;. хотя.

Функции Arrow медленно становятся жизнеспособными для использования. Синтаксис немного короче, что приятно, но я думаю, что функция killer действительно заключается в том, что по умолчанию они всегда привязываются к родительской области.

Это:

var self = this;
var foo = function(a) {

  return self.b + a;

};

Теперь можно написать как:

var foo = a => this.b + a;

Это "самое оптимистичное" использование функций стрелок, но это довольно мило.

И просто для того, чтобы убедить, нет ничего плохого в:

var self = this;

Ответ 10

Мне это нравится. Это "я" - объяснительно. У Дугласа Крокфорда есть кое-что сказать об этом. Он утверждает, что использование "того" является конвенцией. Вы можете бесплатно увидеть Крокфорда, если вы перейдете к юэй-театру и смотрите видеоролики hes о Javascript.