Работа с Scope in Object методами, содержащими ключевое слово this, вызываемое прослушивателями событий. - PullRequest
4 голосов
/ 01 декабря 2011

Я обобщил свое непонимание ситуации на эту маленькую проблему.Вот что, я думаю, я знаю до сих пор:

У меня есть объект myDog (глобальная переменная).Dog имеет переменную-член el, которая является элементом html;потому что это элемент, я могу добавить к нему прослушиватели событий.Поэтому, когда вы нажимаете myDog.el, он записывает в консоль значения this.name и myDog.name.Как и следовало ожидать из-за области действия, this.name не определено, а myDog.name - «Тай».this внутри Dog.speak при вызове прослушивателем события щелчка относится к элементу, по которому щелкнули, переменная-член el, а не объект Dog.* * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * 10 * * * * * * * * * * * * * 10 * *1018* * * * * * * * * * * * * * * * 10 * * * * * *... мои вопросы

1) Какие существуют стратегии для прикрепления объектов к html-элементам, чтобы я мог перейти от this.el обратно к myDog (владелец this.el) без myDogбыть глобальной переменной?

2) Являются ли глобальные переменные в этом случае необходимым злом?И если да, то каковы хорошие стратегии в этом случае, чтобы изящно использовать их?Например, что если я хочу создать 100 собак?Как бы я обработал все эти глобальные переменные в Dog.speak?

Вот версия jsfiddle, если вы хотите поиграть с ней: http://jsfiddle.net/chadhutchins/Ewgw5/

Ответы [ 3 ]

6 голосов
/ 12 мая 2013

"1) Какие существуют стратегии для прикрепления объектов к элементам HTML ..."

Поскольку вы используете .addEventListener(), я бы посоветовал воспользоваться его функцией, о которой мало кто знает, как ... заставить ваш объект Dog реализовать интерфейс EventListener.

Это устанавливает очень четкие отношения между вашими данными Dog и связанным с ними элементом.

Требуются только незначительные изменения. Сначала код ... объяснение ниже.


ДЕМО: http://jsfiddle.net/Ewgw5/1/

function Dog(name,id) {
    this.name = name ? name : "spot";
    this.id = id ? id : "dog";
    this.el = document.getElementById(this.id);

    // ---------------------------------v----no function!
    this.el.addEventListener("click", this);
}

Dog.prototype = {
    // Implement the `EventListener` interface   
    handleEvent: function(event) {
        switch (event.type) {
            case "click": return this.speak();
        }
    },
    speak: function() {
        console.log("this.name: "+this.name+"\nmyDog.name: "+myDog.name);
    }
};

var myDog = new Dog("tye","dog1");

Поэтому все, что я сделал, это передал this в конструкторе addEventListener() вместо передачи функции, а затем я добавил handleEvent() метод к Dog.prototype.

Теперь, когда происходит событие "click", оно вызывает метод handleEvent(). Значение this в этом методе будет вашим Dog экземпляром. Таким образом, оттуда вы можете вызывать любые методы, которые вам нужны.

Поскольку вы сделали элемент свойством this, вы можете получить доступ к элементу через this.el. Но это технически даже не нужно, поскольку элемент также доступен через объект event как event.currentTarget.


"2) Являются ли глобальные переменные в этом случае неизбежным злом ..."

К счастью, нет!


Это поведение должно быть частью вашей прокладки для .addEventListener().

3 голосов
/ 01 декабря 2011

Вы можете попробовать что-то вроде этого:

function Dog(name,id) {
   var self = this;   // <---- NEW BIT saving a reference to this
   this.name = name || "spot"; // <-- unrelated tidy-up to use || instead of ?:
   this.id = id || "dog";
   this.el = document.getElementById(this.id); // given there is a div with a matching    
   this.el.addEventListener("click",function(){ self.speak(); });
        // ignore IE for simplicity (attachEvent has its own 'this' scope issues)
}

С помощью магии замыканий анонимная функция, которую я добавил в addEventListener(), получает доступ к области действия содержащей ее функции даже после возврата содержащейся функциипоэтому он может использовать self, который содержит ссылку на исходный объект, сохраненный из this, когда Dog() был вызван как конструктор.вопросы, которые вы пронумеровали (1) и (2), но, как вы видите, вам не нужны глобальные переменные, чтобы решить эту проблему.С техникой, которую я описал, вы можете создать 100 собак, и все они будут работать.(Ну, они все равно будут говорить: все они будут работать, если вы добавите Dog.prototype.work = function() { }.)

1 голос
/ 01 декабря 2011

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

 this.el.addEventListener("click", this.speak.bind(this));

Этот способ предпочтителен, поскольку не требует выделения области действия для прохождения привязки. Распределение области - одна из самых дорогих вещей в JS.

...