javascript 类和鼠标点击问题

Issue with javascript classes and mouse clicks

所以我正在尝试 class 验证我的 javascript 代码。

我有一个名为节点的 class,它仅包含一个整数、一个用于显示该整数的标签元素和一个用于递增该整数的按钮元素。

当我通过代码调用 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);
}

this 在您的 incrementInteger 函数中没有引用对象上的 属性。创建上下文引用:

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

演示:http://jsfiddle.net/0bgjpp4w

您应该像这样将 this 绑定到您的 incrementInteger

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

如果您的 incrementInteger() 对于使用 'Node' 构造函数创建的每个 'node' 对象都是相同的,那么它可能应该是 prototype!否则(在普通香草 javascript 中)你不会有 shared 方法(和属性)。

使用addEventListener几乎做对了,但是你传递了对象的局部函数而不是对象本身(从而失去对 this 的正确引用,如其他答案中所述。

这个想法是 addEventListener 可以将一个 对象作为第二个参数 ,它将寻找一个名为 handleEvent 的方法并调用它!
无需绑定this;它将正确传递上下文:上下文是您刚刚设置为事件侦听器回调的对象。

这为我们提供了将(否则重复克隆的)incrementInteger 函数移动到构造函数的 prototype 的方法,包括 handleEvent 函数。 不错!

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();
};                                 // });


编辑:

或者(例如)您可以将其简单地写为:

(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 中最接近的实现您(似乎)想要的东西的方法:一个代码块和一个标识符描述 unique[= 'class' 的 共享 部分(因为 'common' javascript 没有 类!)。

或者(例如)使用闭包使私有内容可用(共享)仅对构造函数(第三部分):
(还将构造函数代码重构为仅两行,同时保留原始代码中预期的所有功能。)

(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();
};