2015-01-02 4 views
1

Так что я пытаюсь классифицировать свой код javascript.Проблема с javascript-классами и щелчками мыши

У меня есть класс, называемый узлом, который просто содержит целое число, элемент метки для отображения этого целого числа и элемент кнопки для увеличения целого числа.

Когда я вызываю функцию incrementInteger по коду, все работает так, как ожидалось. Но когда я пытаюсь использовать прослушиватель событий щелчка мыши для вызова функции incrementInteger, все не работает.

Вот мой код:

$(document).ready(function() { 
    var firstNode = new Node(); 
    firstNode.incrementInteger(); 
    var secondNode = new Node(); 
}); 

function Node() { 
    this.integer = 0; 
    this.incrementInteger = function() { 
     this.integer++; 
     this.label.innerHTML = this.integer; 
    } 
    this.addButton = document.createElement("button"); 
    this.addButton.addEventListener("mousedown", this.incrementInteger); 
    this.container = document.createElement("div"); 
    this.label = document.createElement("div"); 
    this.label.innerHTML = this.integer; 

    var bodyElement = document.getElementsByTagName("body")[0]; 
    this.container.appendChild(this.label); 
    this.container.appendChild(this.addButton); 
    bodyElement.appendChild(this.container); 
} 
+1

Если вы используете JQuery, почему все DOM связанные вещи с ванильным JS? – prodigitalson

+0

Любой из двух ответов ниже будет работать (они разные, и один может работать лучше для вас, чем другой), но см. [Эту ссылку] (https://developer.mozilla.org/en-US/docs/Web/ JavaScript/Reference/Operators/this) относительно причины. Короткий вариант заключается в том, что 'this' устанавливается на основе контекста вызова. – peterjb

+0

Спасибо, peterjb, после того, как я увидел решение, мне было любопытно, почему это сработало, а мое - нет, и ваш комментарий помог решить мою путаницу. –

ответ

1

this внутри incrementInteger функции не относятся к собственности на объект. Создание контекстной ссылки:

var self = this; 
this.integer = 0; 
this.incrementInteger = function() { 
    self.integer++; 
    self.label.innerHTML = self.integer; 
} 

Демо: http://jsfiddle.net/0bgjpp4w

+0

Спасибо тон за быстрый ответ и jsfiddle. Это завершилось, и я решил проблему. –

0

Вы должны быть привязки this к вашему incrementInteger так:

this.incrementInteger = function() { 
    this.integer++; 
    this.label.innerHTML = this.integer; 
}.bind(this); 
+0

Спасибо, кучка. Я дал ответ, потому что он ответил первым, но ваш был полезен. Мне пока не хватает репутации, но когда я это сделаю, я позабочусь об этом. –

0

Если incrementInteger() одинакова для всех и каждого 'узла' -объект, созданный с помощью вашего конструктора 'Node', тогда он должен, вероятно, быть prototype! В противном случае (в обычном ванильном javascript) у вас не было бы общих методов (и свойств).

Использование addEventListener вы почти получил это право, но вы прошли функцию локального объекта вместо самого объекта (тем самым теряя правильную ссылку на this, как описано в других ответах).

Идея заключается в том, что addEventListener может занять объект в качестве второго аргумента, что будет искать метод, называемый handleEvent и назвать его!
Не требуется связывание this; он правильно пройдет контекст: контекст - это объект, который вы только что установили как обратный вызов слушателя события.

Это дает нам возможность перемещать (в противном случае повторное клонирование) функцию incrementInteger на конструктор prototype, включая функцию handleEvent. NICE!

function Node(){ 
 
    this.integer = 0; 
 
    this.addButton = document.createElement('button'); 
 
    this.addButton.addEventListener('mousedown', this); 
 
    this.container = document.createElement('div'); 
 
    this.label = document.createElement('div'); 
 
    this.label.innerHTML = this.integer; 
 
    this.container.appendChild(this.label); 
 
    this.container.appendChild(this.addButton); 
 
    document.getElementsByTagName('body')[0].appendChild(this.container); 
 
} 
 

 
Node.prototype={ 
 
    incrementInteger: function(){ 
 
    this.integer++; 
 
    this.label.innerHTML = this.integer; 
 
    }, 
 
    handleEvent: function(){ // track event source-element to overload functionality. 
 
    this.incrementInteger(); 
 
    } 
 
}; 
 

 
// avoiding the html jquery script load line for this snippet 
 
window.onload=function(){   // $(document).ready(function() { 
 
    var firstNode = new Node(); 
 
    firstNode.incrementInteger(); 
 
    var secondNode = new Node(); 
 
};         // });


Edit:

В качестве альтернативы (например), вы могли бы написать это просто как:

(window.Node = function(){ 
 
    var d=document; 
 
    this.container = d.createElement('div'); 
 
    (this.label  = this.container.appendChild(d.createElement('div')) 
 
).innerHTML  = this.integer = 0; 
 
    (this.addButton = this.container.appendChild(d.createElement('button')) 
 
).addEventListener('mousedown', this); 
 
    d.getElementsByTagName('body')[0].appendChild(this.container); 
 
}).prototype={ 
 
    incrementInteger: function(){ 
 
    this.label.innerHTML = ++this.integer; 
 
    } 
 
, handleEvent: function(){ 
 
    this.incrementInteger(); 
 
    } 
 
}; 
 

 

 
window.onload=function(){ 
 
    var firstNode = new Node(); 
 
    firstNode.incrementInteger(); 
 
    var secondNode = new Node(); 
 
};

Выше вы можете видеть, что мы использовали (в коде) идентификатор Node только один раз, поэтому есть только одно место для переименования вашего идентификатора.
Каждый метод (или свойство), который разделяет объект (созданный конструктором), легко отображается под prototype.
Помимо классов ES6, это ближайший вы можете получить в чистом JavaScript, чтобы осуществить то, что вы (кажись) намереваться: один код-блок с один идентификатор, описывающий уникальный и совместно разделы вашего «класса» (поскольку «общий» javascript не имеет классов!).

Или (например), что делает частный материал доступен (общий) конструктору только (третий раздел) с помощью окончания:
(также повторно учитываться конструктор-кода для всего 2 линии, сохраняя при этом все функциональные возможности предназначены в исходном коде.)

(function(ns){ 
 
var b = document, d = b.createElement('div'); 
 
(b = b.createElement('button')).innerHTML = 'Click me'; 
 
    
 
(ns.Node = function(){ 
 
    (this.label  = (this.container = d.cloneNode(false) 
 
        ).appendChild(d.cloneNode(false)) 
 
    ).innerHTML  = this.integer = 0; 
 
    (this.addButton = document.getElementsByTagName('body')[0] 
 
          .appendChild(this.container) 
 
          .appendChild(b.cloneNode(true)) 
 
    ).addEventListener('mousedown', this); 
 
}).prototype={ 
 
    incrementInteger: function(){ this.label.innerHTML = ++this.integer; } 
 
,  handleEvent: function(){ this.incrementInteger(); } 
 
}; 
 
})(window); // pass namespace to hook object-creator 'Node' to. 
 

 

 
window.onload=function(){ 
 
    var firstNode = new Node(); 
 
    firstNode.incrementInteger(); 
 
    var secondNode = new Node(); 
 
};