Javascript多个原型函数 - 如何从另一个调用

tan*_*rwj 4 javascript oop prototype

我最近一直在努力制作更干净的Javascript代码,并使用原型等对象.但我对某些方面感到困惑......

function TimeCard(){
    this.date               = new Date();
    this.pay_period_begin   = null;
    this.pay_period_end     = null; 
}
Run Code Online (Sandbox Code Playgroud)

这是我的timecard对象,带有一些初始值.我有一堆函数,我已经编写过,而且还有更多属于那个时间卡的函数,如果我理解正确的话,它们将是原型函数.以下是我到目前为止的一些内容:

TimeCard.prototype = {         
    init : function(){
        this.pay_period_begin   = $("#pay_period_begin");
        this.pay_period_end     = $("#pay_period_end");
    },
    getTimeCardData : function(){
          //ajax request
    },
    selectAll : function(){
        this.getTimeCardData();
    }
    ...
};
Run Code Online (Sandbox Code Playgroud)

我的问题是当我试图调用this.getTimeCardData()它时说我的对象没有这样的方法.我显然可以访问其他变量,因为它们是在我的构造函数中声明的,但我不明白我猜的原型范围.到目前为止,我已经通过解决此得到tc.getTimeCardData()代替this.getTimeCardData(),与tc是我对象的实例对外宣称- var tc = new TimeCard();.我敢肯定,这不是正确的方法,但是这是什么?

T.J*_*der 8

我的问题是当我试图调用this.getTimeCardData()它时说我的对象没有这样的方法.

听起来好像this不再是指您的实例了.你必须向我们展示我们确实要求的实际调用,但是在JavaScript中,this主要是通过如何调用函数来设置,而不是在它定义的位置,因此this最终变得不同的东西相当容易.

这是一个假设的例子:

TimeCard.prototype = {
    // ...
    doSomething: function() {
        // here, `this` probably refers to the timecard
        someArray.forEach(function() {
            this.getTimeCardData(); // <=== Problem, `this` has changed
        });
    }
    // ...
};
Run Code Online (Sandbox Code Playgroud)

如果我呼叫this.doSomething();一个TimeCard对象,则在呼叫this中将引用时间卡.但在forEach回调中,this将不再引用时间卡.所有类型的回调都会发生同样的变化; 阿贾克斯等

要解决它,你可以记住this一个变量:

TimeCard.prototype = {
    // ...
    doSomething: function() {
        var thisCard = this;
        someArray.forEach(function() {
            thisCard.getTimeCardData(); // <=== Problem
        });
    }
    // ...
};
Run Code Online (Sandbox Code Playgroud)

根据您的具体情况,还有其他各种方法可以解决这个问题.例如,你有selectAll电话getTimeCardData.但是假设selectAll用错误的this值调用?在你的评论中,你说你这样做:

$('#container').on('click', '#selectAll', tc.selectAll);
Run Code Online (Sandbox Code Playgroud)

这意味着selectAll调用时,this将引用DOM元素,而不是对象.

在这种特定情况下,您有三种选择:

  1. 由于你正在使用jQuery,你可以使用$.proxy它接受一个函数和一个值来使用this,并返回一个新的函数,当被调用时,它将调用this设置为所需值的原始函数:

    $('#container').on('click', '#selectAll', $.proxy(tc.selectAll, tc));
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用ES5 Function#bind,它做同样的事情.请注意IE8及更早版本没有它,除非你包含一个"ES5垫片"(因此我$.proxy在上面注意到;你知道你有这个):

    $('#container').on('click', '#selectAll', tc.selectAll.bind(tc));
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用闭包(不要让名字打扰你,闭包不复杂):更多(在我的博客上):

    $('#container').on('click', '#selectAll', function() {
        tc.selectAll();
    });
    
    Run Code Online (Sandbox Code Playgroud)

在上述所有情况中,您将失去this引用DOM元素的好处.在这种特殊情况下,您可能并不关心,但如果您这样做,则可以从事件对象的currentTarget属性中获取它.举例来说,这就要求tc.selectAllthis提及tc和传递什么一直this(DOM元素,你勾搭上的处理程序)作为第一个参数:

$('#container').on('click', '#selectAll', function(e) {
    tc.selectAll(e.currentTarget);
});
Run Code Online (Sandbox Code Playgroud)

另一种不太可能的可能性与您的更新方式有关TimeCard.prototype.你正在这样做的方式,可以new TimeCard() 替换TimeCard.prototype对象的代码运行之前创建对象,这意味着他们将拥有旧的原型.

一般来说,我强烈建议不要替换为prototype构造函数的属性自动创建的对象.相反,只需添加到已存在的对象,如下所示:

function TimeCard(){
    this.date               = new Date();
    this.pay_period_begin   = null;
    this.pay_period_end     = null; 
}
TimeCard.prototype.getTimeCardData = function(){
      //ajax request
};
// ...
Run Code Online (Sandbox Code Playgroud)

原因如下:时间.如果替换属性上的对象,则执行替换之前prototype创建的任何对象都将具有旧原型,而不是新原型.new TimeCard()

我还建议始终在范围函数中创建这些,以便您知道声明和原型添加同时发生:

var TimeCard = (function() {
    function TimeCard(){
        this.date               = new Date();
        this.pay_period_begin   = null;
        this.pay_period_end     = null; 
    }
    TimeCard.prototype.getTimeCardData = function(){
          //ajax request
    };
    // ...

    return TimeCard;
})();
Run Code Online (Sandbox Code Playgroud)

......主要是因为它可以防止时间问题.