JavaScript 命名空间和事件监听器中的“this”问题
Posted
技术标签:
【中文标题】JavaScript 命名空间和事件监听器中的“this”问题【英文标题】:Problems with "this" in JavaScript namespaces and event listeners 【发布时间】:2011-09-05 13:29:13 【问题描述】:首先,我尝试在我的 javascript 程序中使用虚假命名空间,如下所示:
// Ish.Com namespace declaration
var Ish = Ish || ;
Ish.Com = Ish.Com || ;
// begin Ish.Com.View namespace
Ish.Com.View = new function()
var privateVariable;
this.publicFunction = function()
this.publicFunction2()
;
this.publicFunction2 = function() ... ;
;
我并不热衷于使用this
调用其他函数,但直到最近,它仍然有效。但是,我已经为某些元素添加了事件侦听器,它们将 this
解释为目标对象。
我知道我可以使用完整的命名空间而不是 this
来调用我的侦听器 (Ish.Com.View.publicFunction2()
) 内部的函数,但是侦听器经常调用一个函数,然后调用另一个函数。我几乎需要在每个函数调用中使用整个命名空间。
我怎样才能让命名空间与事件侦听器很好地协同工作?我还对实现命名空间的更好方法感兴趣,因为使用 this.publicFunction2()
很笨重。
我对最佳实践非常感兴趣,并学习如何用 JavaScript 编写架构良好的应用程序。但是,除非我对 JavaScript 有更透彻的了解,否则框架是不可能的。
【问题讨论】:
您能否提供一个如何绑定事件侦听器的示例?var clickListener = function(e) ... ;
canvas.addEventListener("click", clickListener, false);
Mozilla对这个问题有很好的解释和解决方案here
监听器经常调用一个函数,一个函数调用另一个,然后另一个...你只需要以正确的方式调用第一个函数。例如。 clickListener = function()Ish.Go.View.publicFunction2()
。使用Ish.Go.View.publicFunction2.bind(Ish.Go.View)
或function() var view = Ish.Go.View; view.publicFunction2();
并没有太大区别。
@Felix 我实际上采用了这种方法,并将我的呼叫限制在听众内部。我担心使用 bind() 会使习惯于 this
引用事件侦听器内的目标对象的人感到困惑。
【参考方案1】:
看来我今天早上一直在以同样的方式回答每个问题:-)
你可以使用“.bind()”:
var eventHandler = yourObject.someFunction.bind(yourObject);
这将保证this
将在任何时候调用“eventHandler”时引用“yourObject”。
“bind()”函数在较新的浏览器中的 Function.prototype 对象上。 Mozilla docs 包含一个可靠的“bind()”实现,可用于修补旧版浏览器。
“bind()”的作用是返回一个新函数,该函数明确安排this
按照您的规定进行绑定。如果您愿意,您还可以传递要传入的参数。使用“bind()”的替代方法是将函数调用包装在您自己的匿名函数中:
var eventHandler = function() yourObject.someFunction(); ;
【讨论】:
所有流行的 Javascript 库也应该有类似的功能,以防你正在使用。 @missingno 是的,这是真的,虽然(在我看来)jQuery "$.proxy()" 真的很弱。 我正在使用 jQuery。是否更喜欢使用 $.proxy() 而不是 JavaScript 的 bind()?我不太关心向后兼容性,因为我正在尝试尽可能多地使用 html5。 @Ishmail Smyrnow 你可以使用任何一个,真的。在 jQuery 代码中使用“.bind()”的一个小麻烦是 jQuery 有自己的“.bind()”函数,这是完全不同的。最重要的是,因为 jQuery “.bind()” 用于注册事件处理程序,你最终会得到一些看起来很疯狂的代码,它混合了 “.bind()” 的两种含义,有些人不喜欢这是可以理解的那 :-) 出于多种目的,“$.proxy()”是完全可以的。 这是个人喜好问题,但是bind()总是让我有一种不安的感觉。它的目的真的归结为使人们不必了解 JavaScript 中的作用域。我想这对短期解决方案很有好处,但对于真正理解 JS 似乎适得其反。【参考方案2】:我不知道我是否完全理解了你的问题。 这符合您的需求吗?
var obj = new function()
var scope = this;
this.fun1 = function()
return scope.fun2();
this.fun2 = function()
//do sth
;
【讨论】:
【参考方案3】:这是由变量上下文和闭包引起的。 “this”总是指当前对象。事件函数本身就是一个对象,“this”指的是那个对象。如果您需要引用父对象,您可以使用前面所述的绑定,或者将父对象“this”设置为变量并在事件函数中使用它。
// Ish.Com namespace declaration
var Ish = Ish || ;
Ish.Com = Ish.Com || ;
// begin Ish.Com.View namespace
Ish.Com.View = new function()
var privateVariable, thisObj=this;
this.publicFunction = function()
thisObj.publicFunction2()
;
this.publicFunction2 = function() ... ;
;
【讨论】:
非常正确。虽然我认为我会使用 bind(),但我感谢您的解释。以上是关于JavaScript 命名空间和事件监听器中的“this”问题的主要内容,如果未能解决你的问题,请参考以下文章