Javascript Object Prototype超出范围

时间:2014-11-17 15:07:34

标签: javascript jquery ajax oop

我目前正在编写一个小的Javascript对象,它会将点击侦听器添加到某些元素上,然后触发对PHP函数的AJAX调用。这一切都正常,但是,我想在AJAX响应时调用一个函数。我通过将一个函数传递给AJAX调用来实现这一点,该函数将在给出响应时触发。

我遇到的问题是,当作为回调传递protoytype时,我正在丢失对象的范围(为了阻止AJAX调用可能发生的不同步问题)。 'this'对象(或self)设置为窗口,而不是我创建的对象的实例。这是我的代码:

    //Rating Submit
var Rater = function(element, videoId, ratingStars, userId) {
    this.userId = userId,
    this.element = element;
    this.videoId = videoId;
    this.ratingStars = ratingStars;
    var self = this;

    jQuery(this.ratingStars).click(function(e) {
        e.preventDefault();
        self.ratingClick(this, self.changeStar);
    });
}

Rater.prototype.ratingClick = function(item, changeStar) {
    jQuery.ajax({
        type     : 'post',
        dataType : 'json',
        url      : 'api/rate-video',
        data     : "userId=" + this.userId + "&videoId=" + this.videoId + "&rating=" + jQuery(item).attr("data-score"),
        success  : function(data) {
            changeStar(data, item);     
        }
    });
}

Rater.prototype.changeStar = function(response, item) {
    var maxCount = jQuery(item).attr("data-score"); 
    //console.log(self);
    jQuery(self.ratingStars).each(function(key, value) {
        alert(key);
    });
}

正如您所看到的,我将'self.changestar'原型函数传递给AJAX调用,以便在给出响应时调用它。当我尝试访问我在该特定实例的构造函数中设置的任何变量时,它表示它是Window对象而不是类的实例。是否可以通过原型函数作为实例内的回调来传递?我希望我已经解释好了......

由于

1 个答案:

答案 0 :(得分:3)

问题是当你这样做时:

self.ratingClick(this, self.changeStar);

你在Rating中遇到了与jQuery点击回调完全相同的问题,你使用self变量解决了这个问题:只有函数引用changeStar被传递,没有任何问题关于在调用它时使用this的值。

一种解决方案是使用Function#bind,您调用函数来获取另一个函数,该函数在调用时将使用特定this值(和可选参数)调用原始函数:< / p>

self.ratingClick(this, self.changeStar.bind(self));

或者,您可以将值分别用作this

self.ratingClick(this, self.changeStar, self);

...然后在成功处理程序中使用Function#call

Rater.prototype.ratingClick = function(item, changeStar, thisArg) { // <== Change here
    jQuery.ajax({
        type     : 'post',
        dataType : 'json',
        url      : 'api/rate-video',
        data     : "userId=" + this.userId + "&videoId=" + this.videoId + "&rating=" + jQuery(item).attr("data-score"),
        success  : function(data) {
            changeStar.call(thisArg, data, item);                   // <=== And here
        }
    });
}