Я только что натолкнулся на интересную ситуацию в JavaScript. У меня есть класс с методом, который определяет несколько объектов, используя объектно-буквенную нотацию. Внутри этих объектов this
указатель используется. Из поведения программы я сделал вывод, что this
указатель ссылается на класс, для которого был вызван метод, а не на объект, создаваемый литералом.
Это кажется произвольным, хотя я ожидаю, что это сработает. Это определенное поведение? Это кросс-браузер безопасно? Есть ли какое-либо объяснение, лежащее в основе того, почему оно выходит за рамки «в спецификации так сказано» (например, является ли это следствием более широкого дизайнерского решения / философии)? Пример урезанного кода:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Ответы:
Каннибализированный из другого моего поста, вот больше, чем вы когда-либо хотели знать об этом .
Прежде чем я начну, вот самое важное, что нужно помнить о Javascript, и повторить для себя, когда это не имеет смысла. У Javascript нет классов (ES6
class
- синтаксический сахар ). Если что-то похоже на класс, это умный трюк. Javascript имеет объекты и функции . (это не на 100% точно, функции - это просто объекты, но иногда полезно думать о них как об отдельных вещах)Эта переменная прикреплена к функциям. Всякий раз , когда вы вызываете функцию, это дается определенное значение, в зависимости от того, как вы вызываете функции. Это часто называют шаблоном вызова.
Существует четыре способа вызова функций в JavaScript. Вы можете вызывать функцию как метод , как функцию , как конструктор и с помощью apply .
Как метод
Метод - это функция, которая прикреплена к объекту.
При вызове в качестве способа, это будет связано с объектом функция / метод является частью. В этом примере это будет связано с foo.
Как функция
Если у вас есть отдельная функция, переменная this будет привязана к «глобальному» объекту, почти всегда объекту окна в контексте браузера.
Это может быть тем, что сбивает вас с толку , но не расстраивайтесь. Многие считают это плохим дизайнерским решением. Поскольку обратный вызов вызывается как функция, а не как метод, поэтому вы видите то, что кажется непоследовательным поведением.
Многие люди решают эту проблему, делая что-то вроде
Вы определяете переменную , которая указывает на это . Закрытие (тема, которой он владеет) сохраняет это , поэтому, если вы вызываете bar как обратный вызов, у него все еще есть ссылка.
ПРИМЕЧАНИЕ. В
use strict
режиме, если используется как функция,this
не привязывается к глобальному. (Этоundefined
).Как конструктор
Вы также можете вызвать функцию в качестве конструктора. Исходя из соглашения об именах, которое вы используете (TestObject), это также может быть тем, что вы делаете, и тем, что вас сбивает с толку .
Вы вызываете функцию как конструктор с новым ключевым словом.
При вызове в качестве конструктора, новый объект будет создан, и это будет связано с этим объектом. Опять же, если у вас есть внутренние функции и они используются как обратные вызовы, вы будете вызывать их как функции, и это будет связано с глобальным объектом. Используйте эту переменную, которая = этот трюк / шаблон.
Некоторые люди думают, что ключевое слово constructor / new было костью, брошенной Java / традиционным программистам ООП, как способ создания чего-то похожего на классы.
С помощью метода Apply
Наконец, у каждой функции есть метод (да, функции - это объекты в Javascript) с именем «apply». Применить позволяет вам определить значение этого параметра , а также позволяет передать массив аргументов. Вот бесполезный пример.
источник
this
будетundefined
для функции вызовов.this
он не имеет ничего общего с областью действия. Вы имеете в виду глобальный объект .this.confusing = 'hell yeah';
то же самое, что иvar confusing = 'hell yeah';
? Так что оба позволятmyObject.confusing
? Было бы неплохо, если бы не только то, что вы можете использоватьthis
для создания свойств и других переменных для внутренней работы.function Foo(thought){ this.confusing = thought; }
а затемvar myObject = new Foo("hell yeah");
Вызовы функций
Функции - это просто тип объекта.
Все объекты Function имеют методы вызова и применения, которые выполняют объект Function, к которому они обращаются .
При вызове первый аргумент этих методов указывает объект, на который будет ссылаться
this
ключевое слово во время выполнения функции - если этоnull
илиundefined
глобальный объектwindow
, для которого используетсяthis
.Таким образом, вызов функции ...
... с круглыми скобками -
foo()
- эквивалентноfoo.call(undefined)
илиfoo.apply(undefined)
, что фактически совпадает сfoo.call(window)
илиfoo.apply(window)
.Дополнительные аргументы to
call
передаются как аргументы для вызова функции, тогда как один дополнительный аргумент toapply
может указывать аргументы для вызова функции как объект, подобный массиву.Таким образом,
foo(1, 2, 3)
эквивалентноfoo.call(null, 1, 2, 3)
илиfoo.apply(null, [1, 2, 3])
.Если функция является свойством объекта ...
... получить доступ к ссылке на функцию через объект и вызвать ее в скобках -
obj.foo()
- эквивалентноfoo.call(obj)
илиfoo.apply(obj)
.Однако функции, содержащиеся в свойствах объектов, не «привязаны» к этим объектам. Как видно из
obj
приведенного выше определения , поскольку функции являются просто типом объекта, на них можно ссылаться (и, таким образом, их можно передавать по ссылке на вызов функции или возвращать по ссылке из вызова функции). Когда ссылка на функции передается никакой дополнительной информации о том, где он был принят с осуществляется с ней, поэтому следующее не происходит:Вызов нашей ссылки на функцию,
baz
не предоставляет никакого контекста для вызова, поэтому он фактически такой же, как иbaz.call(undefined)
, вthis
конечном итоге, ссылаетсяwindow
. Если мы хотимbaz
знать, к чему он принадлежитobj
, нам нужно каким-то образом предоставить эту информацию приbaz
вызове, где вступают в действие первый аргументcall
илиapply
и замыкания.Цепи прицела
Когда функция выполняется, она создает новую область и имеет ссылку на любую вмещающую область. Когда анонимная функция создается в приведенном выше примере, она имеет ссылку на область, в которой она была создана, что является
bind
областью действия. Это известно как «закрытие».Когда вы пытаетесь получить доступ к переменной, эта «цепочка областей действия» обходит переменную с заданным именем - если текущая область не содержит переменную, вы просматриваете следующую область в цепочке и так далее, пока не достигнете глобальный охват. Когда анонимная функция возвращается и
bind
завершает выполнение, анонимная функция все еще имеет ссылку наbind
область действия, поэтомуbind
область действия не «исчезает».Учитывая все вышесказанное, вы должны теперь иметь возможность понять, как работает область действия в следующем примере, и почему будет работать метод для передачи функции вокруг «pre-bound» с определенным значением
this
, когда она вызывается:источник
Да. И да.
Смысл
this
довольно просто вывести:this
используется внутри функции конструктора, и функция была вызвана сnew
ключевым словом,this
ссылается на объект, который будет создан.this
будет продолжать означать объект даже в публичных методах.this
используется где-либо еще, включая вложенные защищенные функции, это относится к глобальной области действия (которая в случае браузера является объектом окна).Второй случай, очевидно, является недостатком дизайна, но его легко обойти, используя замыкания.
источник
В этом случае внутренняя часть
this
связана с глобальным объектом, а не сthis
переменной внешней функции. Это способ, которым разработан язык.См. «JavaScript: Хорошие части» Дугласа Крокфорда для хорошего объяснения.
источник
Я нашел хороший учебник по ECMAScript это
В качестве этого значения контекста может использоваться любой объект.
Эта функция очень важна, потому что, в отличие от переменных, это значение никогда не участвует в процессе разрешения идентификатора. Т.е. при доступе к этому в коде его значение берется непосредственно из контекста выполнения и без какого-либо поиска в цепочке областей действия. Значение этого определяется только один раз при входе в контекст.
В глобальном контексте это значение является самим глобальным объектом (это означает, что это значение здесь равно переменному объекту)
В случае контекста функции это значение в каждом вызове функции может отличаться
Ссылка на Javascript-ядро и главу-3-это
источник