jQuery插件开发如何保持变量和方法的私密性

sma*_*333 6 javascript jquery-plugins private-members prototypal-inheritance

出于练习目的,我正在创建一个jQuery插件,一个简单的图像滑块.我使用Boilerplate中的模式- jQuery插件.

在初始化过程中,一切都按预期工作,每个实例都获得设置所需的正确值(宽度和高度,也包括事件绑定).

当我尝试将计算出的slide-width传递给执行动画的函数(单击下一个按钮)时,麻烦就开始了.我试图保存的每个值都被最后一个实例覆盖 - 好吧,就像我学到的那样,这就是原型继承的作用.

我google了很多,发现(不仅)这个解决方案在stockoverflow:jquery-plugin中的全局变量或局部变量.接受的答案建议存储HTML标记中需要私有的值,data-whatever属性.

这非常好,但不是很好.

第二个答案似乎更优雅,在每个实例的范围内保留真正的私有变量:

(function($) {

$.pluginName = function(element, options) {
....
var plugin = this;
....
        // a public method
    plugin.foo_public_method = function() {
          ....
    }

    // private methods
    var foo_private_method = function() {
          ....
    }
    plugin.init();

} ....
Run Code Online (Sandbox Code Playgroud)

看起来很简单 - 但我无法实现这个解决方案!

所以我的问题是:如何在以下插件模式中实现私有变量?(我如何从Plugin.prototype中正确调用它...)

我用我的插件创建了一个小提琴.代码摘要:

(function ($, window, document, undefined) {

var pluginName = "easyCarousel";

// default configuration object
defaults = {
       ... default values here, css etc
    }
};

// The actual plugin constructor
function Plugin(element, options) {

    this.element = element;
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.init();
}

Plugin.prototype = {

    init: function () {

        var options = this.options;
        this.options.stage = $(this.element);
        .... calling/starting views and controllers

    },

    buildCollectionView: function (options, Helper) {
         .... setting markup, applying css, calulating dimensions 
    },

    buildStageView: function (options, Helper) {

        .... setting markup, applying css
        .... storing calculated slide width in data Attribute

        stage.attr({
            'data-slidewidth': width,
            'data-stagewidth': setWidth
        });
    },

    buildTheatreView: function (options, Helper) {

        .... setting markup, applying css

    },

    buildNavigationView: function (options) {

        .... setting markup

    },


    navigationController: 

    function (options, slideForward, slideBackward) {

        .... event binding

        pubSub.on("navigation:arrownext:click", function (e) {
            slideForward(options, e);
        });

        $('.carousel__arrownext', options.theatre)
        .bind('click', function () {
            pubSub.trigger("navigation:arrownext:click", this);
        });
    },

    slideForwardAnimation: function (options, e) {

       .... reading stored width value from data Attribute

        $element.animate({
            "left": "-=" + slideWidth
        })
    },


    setDimensionsHelper: function (options) {

        .... calculating an returning dimensions of the slider
    },

    eventBusHelper: function (options) {
        // integrating third party eventbus
    }
};

$.fn[pluginName] = function (options) {

    return this.each(function () {
        if (!$.data(this, "plugin_" + pluginName)) {
            $.data(this, "plugin_" + pluginName,
            new Plugin(this, options));
        }
    });    
 }})(jQuery, window, document);
Run Code Online (Sandbox Code Playgroud)

我希望我的代码示例不是复杂/长期查看.

正如您所看到的,我对高级Javascript模式很陌生 - 而且现在我真的卡住了.我已经花了很多时间来解决这个问题.因此,非常感谢每一次提供帮助的尝试.当然还有每个关于代码的评论.

提前致谢 :)

Iso*_*ous 3

您需要做的就是在原型中定义变量(直接或从原型中的方法中定义),而不是在构造函数中定义变量。构造函数中定义的变量将在插件的所有实例之间共享,而原型中定义的变量将是每个实例的。

另外,您的“defaults”定义前面没有“var”关键字,因此您实际上是在创建一个名为“defaults”的全局变量,而不是仅作用于您的闭包的变量。

这就是我的建议:

// default configuration object
var defaults = {
       ... default values here, css etc
    }
};

// The actual plugin constructor
function Plugin(element, options) {
    this._defaults = defaults;
    this._name = pluginName;
    this.init(element, options);
}

Plugin.prototype = {

    init: function (element, options) {
        this.element = element;
        this.options = $.extend({}, this._defaults, options);
        this.options.stage = $(this.element);
        .... calling/starting views and controllers

    },
Run Code Online (Sandbox Code Playgroud)

甚至更好:

// The actual plugin constructor
function Plugin(element, options) {
    this.init(element, options);
}

Plugin.prototype = {

    _name: 'put your name here',

    _defaults: {
        // just define them here, no need for an outside variable
    },

    init: function (element, options) {
        this.element = element;
        this.options = $.extend({}, this._defaults, options);

        // why are you saving stage as an option? That doesn't make sense.
        this.options.stage = $(this.element);
        // Makes more sense to just do this ($el is a more standard name for this)
        this.$el = $(this.element);
        // .... calling/starting views and controllers

    },
Run Code Online (Sandbox Code Playgroud)