2013-05-11 4 views
3

Я, вероятно, что-то не так, но я нашел какое-то интересное поведение при попытке применить некоторое объектно-ориентированное программирование к Javascript. Рассмотрим следующийJavascript «this» overridden event listener

function Bug(element) { 
    this.focusedCell = null; 
    element.addEventListener('click', this.onClick, true); 
}; 

Bug.prototype.onClick = function(event){ 
    console.log("this is: "); 
    console.log(this); 
}; 

Когда я вызываю метод из консоли, я вижу правильный экземпляр «это», но когда я нажимаю на элемент в документе я вижу элемент документа вместо экземпляра. Поэтому ... скорее всего, это не очень хорошая идея использовать прослушиватели событий с помощью методов экземпляра, по крайней мере, так, как я это делаю.

Так что вопрос:

  • Можно ли иметь слушателя событий, как это, что вызывает метод экземпляра объектов JavaScript, сохраняя при этом экземпляр в вызове?

  • Есть ли лучший образец для этого?

Редактировать: Я не пробовал это ни в чем, кроме Chrome. Но я бы предположил, что поведение такое же.

+0

Функция создает новую область видимости. – adeneo

+0

Спасибо, извините, не знал, что это был дублированный поиск, который ничего не обнаружил. – lukecampbell

+0

@FelixKling Wow sweet вы нашли идеальный дубли ... – andlrc

ответ

5

Там это лучший образец, и не требует больших изменений. Сначала я покажу код.

function Bug(element) { 
    this.focusedCell = null; 
    // --------------------------------v----pass the object, not a function 
    element.addEventListener('click', this, true); 
}; 

// Implement the `EventListener` interface 
Bug.prototype.handleEvent = function(event) { 
    if (event.type === "click") 
     this.onClick(event); 
} 

Bug.prototype.onClick = function(event) { 
    console.log(JSON.stringify(this));   // '{"focusedCell":null}' 
    console.log(event.currentTarget.nodeName); // "DIV" 
}; 

Добавляя метод handleEvent, мы делаем Bug реализовать интерфейс EventListener. Это позволяет нам передать новый объект Bug в качестве второго аргумента в addEventListener() вместо функции.

Теперь, когда "click" событие произойдет, метод .handleEvent() будет вызван, и значение this в этом методе будет Bug объект, который был связан.


Поскольку this является ссылка на экземпляр Bug, он, очевидно, не будет ссылка на элемент больше. Но это необязательно, поскольку элемент доступен через event.currentTarget.

Конечно, вы можете добавить элемент непосредственно к своему объекту в конструкторе, если хотите.

DEMO:http://jsfiddle.net/CnZTa/


+0

Это очень изящно, но для IE8 и более ранних требуется также полилиния. – bfavaretto

+0

@bfavaretto: Правда, но OP использует 'addEventListener' уже в вопросе. Не знаю, требуется ли прокладка или уже используется. – 2013-05-11 23:32:27

+0

Мне нравится простота позади этого, у моего фактического класса намного больше обработки событий, и это выглядит прекрасно. Но, как отметил бфаваретто, мне придется взглянуть на более быструю поддержку браузера. – lukecampbell

1

Это нормальное поведение в JavaScript. Вы можете сохранить ваши ожидается this, передав функцию на слушателя:

function Bug(element) { 
    var self = this; // Store a reference to this 
    this.focusedCell = null; 
    element.addEventListener('click', function() { 
     // in here this refers to element 
     self.onClick(event); 
    }, true); 
}; 

Bug.prototype.onClick = function(event){ 
    console.log("this is: "); 
    console.log(this); // In here this refers the an instance of Bug. 
}; 
+0

Код верный, но объяснение не очень ясное. '", передав функцию слушателю "... это то, что делает OP. Разница в том, что функция определена в строке в вашем случае, поэтому она создает закрытие над областью родительской функции, которая позволяет получить доступ к переменной 'self' из функции обработчика. – plalx

5

Вы можете использовать Function.prototype.bind для создания слушателя, связанного с каким-либо это значение, которое вы хотите:

function Bug(element) { 
    this.focusedCell = null; 
    element.addEventListener('click', this.onClick.bind(this), true); 
}; 

пожилых (не ES5) браузеров потребуется полиполк, такой как номер от MDN.