JavaScript/jQuery类中的变量作用域(this)



我正在为我的网站编写简单的滑块。此滑块包含列表项。我想使用OOP方法。

我的实际代码:

var miniSlider = function(objId)
    {
        this.obj = $("#" + objId);
        this.obj.settings = [];
        this.obj.settings['items'] = $('ul li', this.obj).length;
        this.pagerNext = this.obj.find("i.next");
        this.pagerPrev = this.obj.find("i.prev");
        this.pagerNext.on("click", function() {
        alert(this.obj.settings['items']);
        });
    };

我可以调用其他一些滑块(是的,这就是我引入类的原因):

miniSlider("mini-slider");

问题是,当我在jQuery this.pagerNext.on("click",function(){})中时这个不再是我的对象,而是变成了一个点击的元素。如何在点击后以良好的方式访问此.obj.settings(并支持多滑块)?

编辑:

以下是与SOF社区合作创建的完整代码:)

var MiniSlider = function(objId)
{
    this.obj = $("#" + objId);
    this.obj.settings = {
        items: $("ul li", this.obj).length,
        autoChangeTime: 8000
    };
    this.obj.activeElement = null;
    this.pagerNext = this.obj.find("i.next");
    this.pagerPrev = this.obj.find("i.prev");
    var self = this;
    this.pagerNext.on("click", function() {
        self.obj.activeElement = $('li.active', self.obj);
        if(self.obj.settings.items > 0)
        {
            if(self.obj.activeElement.is(':last-child')) 
            { 
                $('li.active', self.obj).removeClass('active');
                $('li', self.obj).first().addClass('active');
            } 
            else 
            {
                self.obj.activeElement.next().addClass('active').prev().removeClass('active');
        }
    }
    });
    this.pagerPrev.on("click", function() 
    {
        self.obj.activeElement = $('li.active', self.obj);
        if(self.obj.settings.items > 0)
        {
            if(self.obj.activeElement.is(':first-child')) 
            { 
                self.obj.activeElement.removeClass('active');
                $('li', self.obj).last().addClass('active');
            } 
            else 
            {
                self.obj.activeElement.prev().addClass('active').next().removeClass('active');
            }
        }
    });
    this.obj.parent().on('mouseenter mouseleave', function(e) {
        if (e.type == 'mouseenter') 
        {
            $(this).addClass('stop');
        }
        else 
        {
            $(this).removeClass('stop'); 
        }
    });
    setInterval(function() {
        if(self.obj.settings.items > 0 && !self.obj.parent().hasClass("stop"))
        {
            self.pagerNext.click();
        }
    }, this.obj.settings.autoChangeTime);
    };

并调用:

new MiniSlider("mini-slider");

Alex在回调中为您提供了this问题的解决方案,但您的代码中还有另一个问题。

您正在调用没有new运算符的miniSlider()函数:

miniSlider("mini-slider");

这意味着在函数内部,this不是唯一的对象,而是window对象!

您需要使用new运算符为每个调用创建一个单独的对象:

new miniSlider("mini-slider");

但您也应该更改此函数的名称,以遵循构造函数以大写字母开头的JavaScript约定。称之为MiniSlider,并像这样使用:

new MiniSlider("mini-slider");

如果您遵循这个约定(大多数有经验的JavaScript程序员都这样做),它将帮助您记住何时使用new。如果函数以大写字母开头,则它是一个构造函数,需要使用new。否则,则不需要。

如果您希望能够在不使用new的情况下使用构造函数,那么也可以使用更多的代码,例如:

function MiniSlider( objId ) {
    if( this == window ) return new MiniSlider( objId );
    // the rest of your constructor code goes here
}

但通常情况下,人们并不在意这一点,只是使用构造函数上的首字母大写来提醒使用new

此外,作为一个建议,当我在变量中保存this时,我喜欢使用一个有意义的名称,然后我会一致地使用该名称,而不是使用this。这样做可能看起来像:

var miniSlider = function(objId) {
    var slider = this;
    slider.obj = $("#" + objId);
    slider.obj.settings = [];
    slider.obj.settings['items'] = $('ul li', slider.obj).length;
    slider.pagerNext = slider.obj.find("i.next");
    slider.pagerPrev = slider.obj.find("i.prev");
    slider.pagerNext.on("click", function() {
        alert(slider.obj.settings['items']);
    });
};

为什么我更喜欢这种方法,而不是在大多数地方使用this,在需要的地方使用另一个变量self?这样,我就不必记住该使用哪个了:我可以始终在代码中使用slider而不是this。(当然,你可以使用self或任何其他名称;如果我要编一个名字,我只想有一个更有意义的名称。)

代码中的另一个小问题是这两条语句:

    slider.obj.settings = [];
    slider.obj.settings['items'] = $('ul li', slider.obj).length;

当你要给它这样的命名属性时,你不应该使用Array。请改用Object。只有当你有0、1、2等数字索引时,才应该使用数组。使用对象文字,你可以同时设置属性:

    slider.obj.settings = {
        items: $('ul li', slider.obj).length
    };

此外,当您使用该属性时:

        alert(slider.obj.settings['items']);

你可以更简单地写为:

        alert(slider.obj.settings.items);

无论哪种方式,它都会做同样的事情。

在本地变量中保存对此的引用,并在嵌套函数中使用该变量而不是this

var self = this;
this.pagerNext.on("click", function() {
  alert(self.obj.settings['items']);
});

最新更新