JavaScript, используя «это» в глобальном объекте - PullRequest
1 голос
/ 30 марта 2010

На что ссылается ключевое слово this при использовании в объекте gloabl?

Скажем, например, у нас есть:

  var SomeGlobalObject =
  {
     rendered: true,
     show: function()
     {
        /*
        I should use 'SomeGlobalObject.rendered' below, otherwise it 
        won't work when called from event scope.
        But it works when called from timer scope!!
        How can this be?
        */
        if(this.rendered)
           alert("hello");
     }
  }

Теперь, если мы вызовем встроенный скрипт на странице HTML:

SomeGlobalObject.show();
window.setTimeout("Msg.show()", 1000);

все работает нормально.

Но если мы сделаем что-то вроде

AppendEvent(window, 'load', Msg.show);

мы получаем ошибку, поскольку this.rendered не вызывается при вызове из области действия события.

  1. Знаете ли вы, почему это происходит?
  2. Не могли бы вы объяснить, есть ли другой разумный способ сделать это без необходимости каждый раз переписывать SomeGlobalObject.someProperty в код SomeGlobalObject?

Спасибо!

AppendEvent - это простая кросс-браузерная функция для добавления события, код которого приведен ниже, но это не имеет значения для ответа на поставленные выше вопросы.

  function AppendEvent(html_element, event_name, event_function)
  {
        if(html_element.attachEvent) //IE
           return html_element.attachEvent("on" + event_name, event_function);
        else
           if(html_element.addEventListener) //FF
              html_element.addEventListener(event_name, event_function, false);
  }

Ответы [ 4 ]

4 голосов
/ 30 марта 2010

Когда вы ссылаетесь на функцию, которая является методом объекта, вы отсоединяете его от этого объекта, и this больше не будет ссылкой на объект.

Самое простое решение - обернуть его в анонимную функцию:

AppendEvent(window, 'load', function () { Msg.show() } );

Существует также метод bind, доступный для функций в реализациях ECMAScript 5-го издания, который позволяет вам сделать это:

AppendEvent(window, 'load', Msg.show.bind(Msg, arg1, arg2));

Среда JS, Prototype, предоставляет этот метод и для текущих реализаций JS. Код (спасибо @bobince):

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}
1 голос
/ 30 марта 2010

Сделай это

var SomeGlobalObject =
  {
     ...
  }

AppendEvent(window, 'load', function(){
    SomeGlobalObject.show();
});

Javascript поддерживает динамическую область видимости. Поэтому SomeGlobalObject будет всегда доступен для функции, объявленной inline.

0 голосов
/ 02 апреля 2010

Простой способ описать, что произошло:

«this» всегда относится к инициатору функции.

Итак, возьмите оскорбительный случай:

AppendEvent(window, 'load', Msg.show);

Обработка событий вызывается окном. Таким образом, «это» становится окном и

window.rendered

не определено.

bind () быстро станет вашим лучшим другом: -)

В сторону

window.setTimeout("Msg.show()", 1000);

будет работать немного быстрее, если вы предоставите объект функции напрямую

window.setTimeout(Msg.show, 1000);

Это потому, что для первого синтаксиса требуется eval () строки - в основном компиляция - прежде чем он может быть вызван

0 голосов
/ 30 марта 2010

Ключевое слово this всегда относится к вызывающему объекту. В первом примере SomeGlobalObject является вызывающей стороной.

Я полагаю, вам нужно сделать что-то вроде AppendEvent(window, 'load', function() { SomeGlobalObject.show() })

...