为网页创建模块化JavaScript代码时,我经常需要将事件附加到例如纽扣。
采用以下示例代码,通常位于AMD模块中:
define(function(require) {
var MyObject = function(ele) {
this.ele = ele;
}
MyObject.prototype = {
myfunct: function() {
console.log('myfunct called');
}
}
return MyObject;
});
稍后在页面上我会这样做:
$(document).ready(function() {
var button = $('#button'),
myobj = new MyObject(button);
button.click(function() {
myobj.myfunct();
});
});
这很有效,但我认为似乎有点不洁净。
例如,我需要在全局命名空间中创建至少一个变量来将函数绑定到按钮。此外,当页面上有许多JavaScript驱动的交互时,代码变得混乱 - 这是我最初想通过使用模块化JavaScript解决的问题。
这就是我的想法是为了原型中的事件绑定:
var MyObject = function(ele) {
self = this;
this.element = ele;
this.init();
}
MyObject.prototype = {
init: function() {
$(this.element).click(function() {
self.myfunct();
});
},
myfunct: function() {
console.log('myfunct called');
}
}
这样,模块外部的代码看起来像这样:
$(document).ready(function() {
var button = $('#button'),
myobj = new MyObject(button);
});
将事件绑定移动到原型中是否明智?如果是这样,我可以采用init()
的方式吗?
此外,我注意到当页面上有两个按钮时,某些上下文丢失 - self
始终引用MyObj
的最后一个实例。
为什么会发生这种情况 - 我想使用self = this;
我可以阻止上下文?
答案 0 :(得分:1)
让我们从第二个问题开始。代码的问题在于您将self
声明为全局变量,因为您忘记/省略了var
关键字。因此,当您创建两个或更多实例时,最后一个实例会覆盖前一个实例,并且所有点击事件中的self
都会指向最后一个实例。
检查固定代码。请注意,您必须将var self = this
移动到init方法,因为现在它是本地变量:
var MyObject = function(ele) {
this.element = ele;
this.init();
}
MyObject.prototype = {
init: function() {
var self = this;
$(this.element).click(function() {
self.myfunct();
});
},
myfunct: function() {
console.log('myfunct called');
}
}
至于第一个问题,它的设计是否合适,并没有任何问题。 init
方法中的绑定事件确实更清晰。
答案 1 :(得分:1)
按照您的方式进行事件绑定没有任何问题。你失去范围的原因是因为你做了
self = this;
在构造函数中创建self作为全局变量。因此,每次调用构造函数时,它都会将self设置为该实例。
要修复它,请在init函数中将self设置为局部变量:
MyObject.prototype = {
init: function() {
var self = this; // <-- this is the fix
$(this.element).click(function() {
self.myfunct();
});
}
答案 2 :(得分:1)
好的,首先self
发生了什么。
这一行:
self = this;
您正在创建一个名为self
的全局变量,每次调用构造函数时都会被覆盖。如果您使用严格模式,可以很容易地检测到这一点。此外,如果您正确使用了局部变量,那么您的原型将不知道self
是什么,因此您尝试在原型中使用self
会被破坏。
我认为你的两种方法都存在问题:
作为补救措施,我建议采用以下方法:
var MyObject = function(ele) {
this.element = ele;
}
MyObject.prototype = {
attachEvents: function() {
var self = this;
$(this.element).click(function() {
self.myfunct();
});
},
myfunct: function() {
console.log('myfunct called');
}
};
$(document).ready(function() {
var button = $('#button'),
myobj = new MyObject(button);
myobj.attachEvents();
});
这需要在实例化MyObject
的人的一个额外步骤,但它清楚地传达了将事件附加到myobj
的封装元素的意图。它也不需要使用MyObject
的人对你的第一种方法进行错综复杂的操作。