Javascript: 将面向对象的方法附加到事件和'this'关键字

4

我刚接触面向对象的JavaScript,对于“this”关键字和事件处理有些困惑。

我的目标是:我有多个DOM对象,不仅要将一个公共事件绑定到它们上面,还要在全局容器中保存这些对象的一些数据(以提高运行时性能)。

所以,我基本上是这样做的:

function ClassThatDoesSomething() {
    /* keeps node ids for processing in this.init */
    this.nodes = new Array();

    /* keeps processed node data for fast access */
    this.nodeData = new Array();

    this.sthAddNodes = function(/* ids */) {
        /* appends node ids to local variable (this.nodeData) */
    }

    function init() {
        /* gathers data from all nodes that were 
           added before and stores it in this.nodeData */

        /* here, unsurprisingly, 'this' references the window element*/

        addEvent(window,'scroll',this.scroll);
    }

    function scroll() {
        /* do stuff when user scrolls the page */

        /* 'this' references the window element here too */
    }
    addEvent(window,'load',this.init);
}

稍后,在文档正文中,我可以添加以下内容:
var Ctds = new ClassThatDoesSomething();

接着,通过以下方法添加DOM元素:

Ctds.addNodes(ids);

不需要进一步的实现代码。

问题:如何在initscroll方法中访问JS类实例,而不是window元素

它不必通过this关键字,我知道,但我仍然想不出什么。

P.S.

  • addEvent是一个极为基本的函数,用于附加事件,它只是IE/Fx友好,并且不执行其他操作。
  • 我正在编写的代码已经具有功能性,但以过程化形式,我只是想将其转换为面向对象。
  • 作为一个次要的子问题,我得到了这样的印象,即getter/setter方法在javascript中被不鼓励使用,如果我使用它们可以吗?
7个回答

10

我注意到的一件事是,无论是init还是scroll都不是实例的方法。

因此,你只需要在加载事件中添加init而不是this.init

addEvent(window,'load',init); // No "this." needed

同样地:

addEvent(window,'scroll',scroll);
如果您决定将它们移动到类中(例如this.scrollthis.init等),则可以保存对this的引用,并在传递给addEvent的匿名函数中引用它:
var self = this;

this.init = function() {
    addEvent(window, 'scroll', function() {
        self.scroll()
    })
};

this.scroll = function() { /* ... */ };

addEvent(window,'load',function() {
    self.init()
});

这被称为一个闭包


哇,这么多答案,我有点不知所措,谢谢大家。那么,一个方法应该如何定义呢?(问题有点蠢,抱歉) - raveren
@Raveren:这是一个很大的问题。这个代码示例是Crockford所谓的“特权”成员声明的一个例子。请参阅http://www.crockford.com/javascript/private.html。这实际上是JavaScript中面向对象编程的高级方法。如果您想从JavaScript中定义类的基础开始,请从这里开始:http://mckoss.com/jscript/object.htm。 - Roatin Marth

2
function MyConstructor() {
    this.foo = "bar";
    var me = this;
    function myClosure() {
        doSomethingWith(me.foo);
    }
}

1

this 直到函数执行时才确定。当附加事件侦听器时,您正在传递一个 函数,它不带有作用域。因此,在指定的事件上,该函数在 window 的范围内运行,这意味着 this 将等于 window。要强制在特定范围内执行,请使用诸如创建一个新变量等于 this 的技巧,例如:

var that = this;
...
addEvent(window,'scroll', function() {
    that.scroll()
});

1
给Function原型添加一个方法,允许你将任何函数绑定到任何对象上:
Function.prototype.bind = function(object) {
   var __method = this;
   return function() {
      return __method.apply(object, arguments);
   };
};

在实例中声明您的事件处理程序(保持整洁):

function ClassThatDoesSomething() {

  this.events = {
    init: ClassThatDoesSomething.init.bind(this),
    scroll: ClassThatDoesSomething.scroll.bind(this),
    etc: ClassThatDoesSomething.etc.bind(this)
  };
  ...
}

现在,每当您引用事件时,它们将自动绑定到类实例。例如:
function init() {
  addEvent(window,'scroll',ClassThatDoesSomething.events.scroll);
}

0

您可以使用闭包来实现:

function ClassThatDoesSomething() {
    var self=this;
    // ...

    function init() {
        addEvent(window,'scroll',self.scroll);
    }
}

它不起作用是因为我只是复制了“function init()”,而没有将其变成“this.init = function()”。你认为这不是闭包吗? - Mikhail Korobov
同样重要的是这个类如何被使用。正确的代码是'var myClassInstance = new ClassThatDoesSomething(); myClassInstance.init();'。 - Mikhail Korobov

0
做这个:
var ClassThatDoesSomething = function() {
    /* keeps node ids for processing in this.init */
    this.nodes = new Array();

    /* keeps processed node data for fast access */
    this.nodeData = new Array();
}

ClassThatDoesSomething.prototype.sthAddNodes = function(/* ids */) {
        /* appends node ids to local variable (this.nodeData) */
    }
}

ClassThatDoesSomething.prototype.init = function() {
        /* gathers data from all nodes that were 
           added before and stores it in this.nodeData */

        /* here, unsurprisingly, 'this' references the window element*/

        addEvent(window,'scroll',this.scroll);
    }
}
ClassThatDoesSomething.prototype.scroll = function() {
        /* do stuff when user scrolls the page */

        /* 'this' references the window element here too */
    }
    addEvent(window,'load',this.init);
}

-1
这个技巧应该有效:
function ClassThatDoesSomething() {
...
    this.This = this;
...
}

然后在那些有问题的方法中,你可以使用'This'

希望这能帮到你。


这个代码 this.This = this 真是让我无法理解。 - Roatin Marth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接