Избегайте потери этой ссылки и почему это происходит - PullRequest
0 голосов
/ 16 ноября 2011

У меня есть эта скрипка с ошибкой -> http://jsfiddle.net/Osoascam/AkZZr/6/ (Это версия без ошибки) -> http://jsfiddle.net/Osoascam/AkZZr/7/

В нем есть Модуль (как и основное приложение), Module.AjaxInterface, который имеет дело с вызовами Ajax, Module.Modules.Inbox (который выполняет задачи, связанные с входящей электронной почтой), и Module.Pages.Gmail, который имеет дело с несколькими модули для отображения страницы. Все это делается с использованием шаблона модуля.

Теперь вы можете видеть, что существует множество обратных вызовов. Я хотел бы знать, что происходит с this на этих вызовах ...

Что я не понимаю, так это то, что происходит со ссылкой this и как я могу ее сохранить:

getMessages: function(params) {
                var parameters = params || {};
                params = {
                    // Please note I'm using this, which equals the module
                    successCallback: this.pretendRender,
                    successCallbackParameters: parameters,
                    json: params.json
                };
                var test = new Module.AjaxInterface(params);
                test.ajaxCall();
            },

Итак, вызов функции внутри самого модуля работает ... Затем он вызывает test.ajaxCalls, что в свою очередь вызывает pretendRender(). Теперь, на pretendRende r у меня есть это:

 pretendRender: function(data, parameters) {
                // LINE 106 that is causing the ERROR
                // It says "this.addColor() is not defined and THIS = window now
                data.color = this.addColor();
                parameters.successCallback(data);
            },

            addColor: function() {
              return "#AD9";
           }

Мой вопрос ... Что происходит со ссылкой this? Почему он меняется на window? Как я могу это исправить? Я знаю, что мог бы использовать call или apply, но функция pretendRender вызывается на AjaxInterface, и ссылка на Modules.Inbox была потеряна (если я не использую caller, что я не могу под "strict"). Я знаю, что могу передать this на AjaxInterface, чтобы сохранить его, но я действительно хочу по-настоящему понять, что происходит, и создать элегантное решение.

Ответы [ 2 ]

4 голосов
/ 16 ноября 2011

this.pretendRender - это просто ссылка / указатель на функцию, контекст this при вызове функции зависит от многих вещей:

a.b.c = this.pretendRender;
a.b.c(); 

this будет b внутриc потому что функция, на которую ссылается c, вызывается как свойство b


window.a = this.pretendRender;
a(); 

this будет установлено на global object, потому что функция, на которую ссылается a вызывается как свойство global object


a.b.c = this.pretendRender.bind( this );
a.b.c();

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


a.b.c = this.pretendRender;
a.b.c.call( someObject );

this будет someObject внутри c, потому что этоявно указано.


Поскольку вы используете jQuery, вместо this.pretendRender.bind( this ); вы можете использовать successCallback: $.proxy( this.pretendRender, this )

jsfiddle

2 голосов
/ 16 ноября 2011

this - это всегда объект, для которого вызывается функция. Меняется. this.pretendRender не является методом, прикрепленным к объекту this в данный момент времени. Это просто передаваемая функция. Если вы хотите гарантировать, что this в этом контексте перемещается вместе с методом, вам необходимо привязать this к этой функции. Примерно так (используя замыкание):

var me = this;
params = {
    successCallback: function() { return me.pretendRender.apply(me, arguments); },
    ...
}

Платформа underscore.js имеет значительно лучший способ сделать это с помощью _.bind().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...