Это ссылка в Javascript, вероятно , один из самых запутанных понятий для определения объема людей , приходящих на новый язык. Понимая, этот справочник позволяет вам раскрыть тайны объектно-ориентированного Javascript и получить лучшее / более интуитивное понимание структуры объектной модели.
Явно устанавливая эту ссылку
Вот небольшой код, который поможет нам
function setVar(arg) { this.var = arg; } var obj = Object.create(null); obj.setVar = setVar; obj.setVar('hello'); console.log(obj.var); // => 'hello'
Что тут происходит?
- — Мы объявляем функцию setVar, которая устанавливает свойство «var» того, на что указывает ссылка «this», полученному аргументу.
- — Затем мы создаем объект с именем «obj», назначаем его свойство «setVar» для функции setVar
- — Наконец, мы вызываем функцию setVar через объект obj
Выполнив этот код, вы увидите, что объект obj теперь имеет свойство var, установленное в ‘hello’. Несмотря на то, что нигде в нашем коде мы не делаем:
obj.var = 'hello';
Как это? При вызове object.method () эта ссылка устанавливается на объект в пределах границ методы . В приведенном выше случае, поскольку мы вызывали obj.setVar, для этой ссылки было установлено значение obj в пределах метода setVar. А так, SetVar добавляет свойство вар к тому , что он это есть, OBJ был одарен вар собственности.
Установка этой ссылки с помощью «вызова» или «применить»
Javascript позволяет вам указать, какой будет ссылка this при вызове функции, используя функции call () или apply () . Формат вызова () :
SomeFunction.call(the_this_object, *arguments)
Переписав предыдущий пример для использования call ()
function setVar(arg) { this.var = 'hello'; } var obj = Object.create(null); setVar.call(obj, 'hello'); console.log(obj.var); // => 'hello'
Как видите, это выглядит немного более гибким и иногда лучше, чем подход object.method () . Функция apply () идентична call () с той лишь разницей, что последний аргумент — это массив, а не ваши аргументы, разделенные запятой. Если бы мы вместо этого использовали apply (), это было бы:
setVar.apply(obj, ['hello']);
Захват этой ссылки
Вы можете часто видеть код, который делает:
var that = this; .... Some code follows ....
И вы можете удивиться, почему они это делают. Внутри каждого вызова функции эта ссылка сбрасывается. Так, например:
function outer() { this.foo = 'blah'; function inner() { console.log(this.foo); } inner(); } var obj = Object.create(null); outer.call(obj);
Запуск этого приводит к тому, что в журнале регистрируется неопределенное число . Почему это? Эта ссылка в наружном установлена в OBJ , так как мы явно делаем это с помощью вызова () функции. Однако, в внутренней () в этом ссылка указывает на другой объект, поэтому протоколирование Foo свойство этого в внутренней () привела к неопределенным.
Как мы это исправим? Один из способов — захватить эту ссылку и использовать ее.
function outer() { var that = this; that.foo = 'blah'; function inner() { console.log(that.foo); } inner(); } var obj = Object.create(null); outer.call(obj);
Другим способом было бы вызвать inner () с помощью функции call (), передавая ему this из external. Лично я думаю, что это более читабельно.
Использование функции связывания
Javascript также позволяет вам привязать ссылку this к функции, поэтому все будущие вызовы этой функции будут использовать объект, к которому вы изначально привязали функцию. Это полезно, когда вы не хотите помнить об использовании функции call () . Пример bind ()
function setFoo() { this.foo = 'bar'; } var obj = Object.create(null); var boundSetFoo = setFoo.bind(obj); boundSetFoo(); console.log(obj.foo); // 'bar'
Здесь мы создаем ограниченную ссылку на функцию setFoo () под названием boundSetFoo с объектом obj, являющимся this . Этот способ получения этого особенно полезен при работе с событиями и обработчиками событий.
function eventHandler(evt) { if(!this.eventsReceived) { this.eventsReceived = []; } this.eventsReceived.push(evt); console.log('event is %s', evt); } var evtEmitter = Object.create(events.EventEmitter.prototype); var obj = Object.create(null); evtEmitter.on('some_event', eventHandler.bind(obj)); var someOtherObj = Object.create(null); evtEmitter.on('some_event', eventHandler.bind(someOtherObj)); obj.emit('some_event', 'hi there');
Здесь мы имеем два объекта OBJ и someOtherObj оба из которых подписались на some_event события на evtEmitter объекта. Обратите внимание, как мы повторно используем функцию eventHandler, но настраиваем ее для привязки к нужному объекту именно тогда, когда нам это нужно. Аккуратно, а?
TL; DR
Javascript очень податлив, позволяя вам подчинить его своей воле. Эта гибкость позволяет вам придумывать невероятно элегантные решения для, казалось бы, неразрешимых проблем. Но эта гибкость означает, что писать плохой код тоже довольно просто.