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”问题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 命名空间和 jQuery 事件处理程序

jquery的事件命名空间详解

两个不同的命名空间连接到同一个事件

js中的监听事件总结

事件监听器,JavaScript

Javascript 命名空间、onclick 事件等