Javascript多个原型函数 - 如何从另一个调用 [英] Javascript multiple prototype functions - how to call one from another

查看:74
本文介绍了Javascript多个原型函数 - 如何从另一个调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}

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

  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();
}
...
};

我的问题是,当我尝试调用 this.getTimeCardData()时/ code>它说我的对象没有这样的方法。我显然可以访问其他变量,因为它们是在我的构造函数中声明的,但我不明白我猜的原型范围。到目前为止,我通过使用 tc.getTimeCardData()而不是 this.getTimeCardData()来解决这个问题。 code> tc 是我在外面声明的对象的实例 - var tc = new TimeCard(); 。我确定这不是正确的方法,但这是什么?

解决方案


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


听起来像这个不再是指您的实例了。您必须向我们展示我们确实要求的实际调用,但在JavaScript中,主要由函数的设置方式设置,而不是它定义的地方,所以这个很容易就会变得不同了。



这是一个假设的例子:

  TimeCard.prototype = {
// ...
doSomething:function() {
//这里,`this`可能是指时间卡
someArray.forEach(function(){
this.getTimeCardData(); //< ===问题,`这个`已改变
});
}
// ... ...
};

如果我打电话给 this.doSomething(); TimeCard 对象上,在通话中,此将引用时间卡。但是在 forEach 回调中,将不再引用时间卡。所有类型的回调都会发生同样的变化; ajax等。



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

  TimeCard.prototype = {
// ...
doSomething:function(){
var thisCard =这个;
someArray.forEach(function(){
thisCard.getTimeCardData(); //< === Problem
});
}
// ... ...
};

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

  $('#container')。on('click' ,'#selectAll',tc.selectAll); 

这意味着当调用 selectAll 时, 将引用DOM元素,而不是您的对象。



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


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

      $('#container')。on('click', '#selectAll',$ .proxy(tc.selectAll,tc)); 


  2. 使用ES5的功能#bind ,它做同样的事情。请注意IE8及更早版本没有它,除非你包含一个ES5垫片(因此我注意 $。proxy 以上;你知道你()<($') .bind(TC));


  3. 使用闭包(不要让名字打扰你,闭包是并不复杂)
    更多(在我的博客上)

      $('#container')。on('click','#selectAll',function(){
    tc.selectAll();
    });


在上述所有情况中,你将会失去了这个引用DOM元素的好处。在这种特殊情况下,您可能不在乎,但如果您这样做,您可以从事件对象的 currentTarget 属性中获取它。例如,这会调用 tc.selectAll ,其中指的是 tc 并传入 c>这个(你将处理程序挂钩的DOM元素)作为第一个参数:

  $('#container')。on('click','#selectAll',function(e){
tc.selectAll (e.currentTarget);
});








另一种不太可能的可能性与你的方式有关更新 TimeCard.prototype 。您正在这样做的方式,可以通过新的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
};
// ... ...

原因如下:时间。如果替换 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
};
// ...

返回TimeCard;
})( );

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


I've been working a lot lately on making cleaner Javascript code, and using objects with prototypes etc. But I'm confused on some points...

function TimeCard(){
    this.date               = new Date();
    this.pay_period_begin   = null;
    this.pay_period_end     = null; 
}

Here is my timecard object with some initial values. I have a bunch of functions that I've written and more to come that are part of that timecard and, if I understand correctly, they will be prototype functions. Here is some of what I have so far:

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();
    }
    ...
};

My problem is that when I try to call this.getTimeCardData() it says that my object has no such method. I can obviously access the other variables because they are declared in my constructor, but I don't understand how prototype scopes I guess. So far I have gotten around this by using tc.getTimeCardData() instead of this.getTimeCardData(), with tc being the instance of my object declared outside - var tc = new TimeCard();. I'm sure that that's not the correct way to go about this, but what is?

解决方案

My problem is that when I try to call this.getTimeCardData() it says that my object has no such method.

It sounds like this is no longer referring to your instance. You'll have to show us the actual call for us to be sure, but in JavaScript, this is set primarily by how a function is called, not where it's defined, and so it's fairly easy for this to end up being something different.

Here's a hypothetical example:

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

If I call this.doSomething(); on a TimeCard object, within the call this will refer to the timecard. But within the forEach callback, this will no longer refer to the timecard. The same sort of thign happens with all kinds of callbacks; ajax, etc.

To work around it, you can remember this to a variable:

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

There are also various other ways to work around it, depending on your specific situation. For instance, you have selectAll calling getTimeCardData. But suppose selectAll is called with the wrong this value? In your comment, you said you were doing it like this:

$('#container').on('click', '#selectAll', tc.selectAll);

That means that when selectAll is called, this will refer to the DOM element, not to your object.

You have three options in that specific situation:

  1. Since you're using jQuery, you can use $.proxy, which accepts a function and a value to use as this, and returns a new function that, when called, will call the original with this set to the desired value:

    $('#container').on('click', '#selectAll', $.proxy(tc.selectAll, tc));
    

  2. Use ES5's Function#bind, which does the same thing. Note that IE8 and earlier don't have it unless you include an "ES5 shim" (hence my noting $.proxy above; you know you have that):

    $('#container').on('click', '#selectAll', tc.selectAll.bind(tc));
    

  3. Use a closure (don't let the name bother you, closures are not complicated): More (on my blog):

    $('#container').on('click', '#selectAll', function() {
        tc.selectAll();
    });
    

In all of the above, you'll lose the benefit of this referring to the DOM element. In that particular case, you probably don't care, but if you did, you can get it from the event object's currentTarget property. For instance, this calls tc.selectAll with this referring to tc and passing in what would have been this (the DOM element you hooked the handler on) as the first argument:

$('#container').on('click', '#selectAll', function(e) {
    tc.selectAll(e.currentTarget);
});


Another, less likely, possibility relates to how you're updating TimeCard.prototype. The way you're doing it, it's possible to create objects via new TimeCard() before your code that replaces the TimeCard.prototype object runs, which means they'll have the old prototype.

In general, I strongly recommend not replacing the object automatically created for the prototype property of the constructor function. Instead, just add to the object already there, like this:

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

Here's why: Timing. If you replace the object on the prototype property, any objects you create via new TimeCard() before you do that replacement will have the old prototype, not the new one.

I also recommend always creating these within a scoping function so you know that the declaration and the prototype additions happen at the same time:

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;
})();

...primarily because it prevents the timing issue.

这篇关于Javascript多个原型函数 - 如何从另一个调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆