如何在jQuery UI小部件工厂小部件中声明静态/类变量

11

关于jquery ui widget factory:

如何使用静态变量/类级别变量,以便在所有实例之间共享?

例如:

$.widget("ui.staticTest", {
    staticVar:'不变',
    test: function(a){
        if(a){
            this.staticVar= a;
        }
        alert(JSON.stringify(this.staticVar));
    }
});

$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','改变');
$('#parent').staticTest('test');

在上述代码中,如果staticVar是静态的,则$('#parent').staticTest('test');将弹出'改变',但实际上它弹出了“不变”。

我能想到的解决方案比较丑陋:

1)$('body').data('sharedVariable', myData) - 这似乎不是好的做法,如果有人或某些事情清除了数据,则怎么办? 2)将其存储在原型命名空间中,例如= $.ui.staticTest.prototype.staticVar = myData; 这也引起了警觉。

(如果您想玩一下此代码,请访问jsfiddle:http://jsfiddle.net/alzclarke/Sx8pJ/

7个回答

26

闭包就是你的答案

(function($) {

var staticVariable = '';

$.widget('ui.newWidget', {
    options: {

    },
    _init: function() {
    }

});

})(jQuery);

由于静态变量被封装在一个立即调用的匿名函数中(就像您应该已经为 jQuery/jQuery UI 插件做的那样),它只能在您刚刚定义的小部件的范围内使用。


1
这是一个很棒的答案,非常简单,与其他答案不同的是,它允许静态变量真正私有化。 - alzclarke
2
我能问一下如何从小部件外部访问(设置)staticVariable吗?我需要一个选项,可以为所有小部件实例配置一次。 - Marc
你可以编写一个函数来实现此功能,并使其具有全局作用域。 - Eric Pigeon

2

看起来小部件没有共享范围。所以我会像你建议的那样,在jQuery UI对象本身上定义一个共享对象。

注意:共享对象名称应反映小部件名称和命名空间。

$.ui.staticShared = { color: "#fff" };

$.widget("ui.static", {
    color: function (o)
    {
        if (typeof o !== "undefined") $.ui.staticShared.color = o;

        return $.ui.staticShared.color;
    }
});

这在我看来是最简洁的方式。当然,有人可能会覆盖共享对象,但即使发生这种情况,也不会导致世界末日。
如果你想要一些故障保护或者反馈,以判断共享对象是否无效或已被覆盖,你可以在“_init”事件中对对象结构进行检查。
$.widget("ui.static", {
    _init: function ()
    {
        if (typeof $.ui.staticShared === "undefined")
        {
            alert("$.ui.staticShared is required for this plug-in to run");
        }
    },
});
_init事件在对象实例化时被触发。

嗨,想法不错,但是你在这里声明和赋值的是全局变量而不是类变量。如果我在代码末尾运行alert(_static);,它也会弹出“bar”。同样,如果调用之前的任何代码使用了这个变量名,那么该值就会丢失。 - alzclarke
@alzclarke:你说得对。_Static被定义在window对象上。发现得很好 :) - cllpse
比我建议的更好,我认为... :> - alzclarke

1

实际上,如果您的变量是一个对象,它会自动变为静态... 嗯嗯嗯嗯嗯,非常有帮助!(不是)... 特别是考虑到包含基元的变量显示相反的行为。这一定与旧的“指针不是对象”习语有关。

无论如何...

如果您的变量包含一个对象 {},则以下将是正确的答案,否则,请参见其他答案:

静态示例:

$.widget("ui.staticTest", {
    staticVar:{val:'unchanged'},
    _create: function(){
    },
    test: function(a){
        if(a){
            this.staticVar.val= a;
        }
        alert(JSON.stringify(this.staticVar.val));
    }
});


$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

http://jsfiddle.net/alzclarke/Sx8pJ/9/

非静态示例:

$.widget("ui.staticTest", {
    _create: function(){
      this.staticVar={val:'unchanged'};
    },
    test: function(a){
        if(a){
            this.staticVar.val= a;
        }
        alert(JSON.stringify(this.staticVar.val));
    }
});


$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

http://jsfiddle.net/alzclarke/Sx8pJ/10/


如果您需要复杂的实例变量,请注意此示例 - 原始类型对于小部件的每个实例都是唯一的,但对象类型在实例之间共享。如果您需要实例对象类型,请将它们作为this.options的一部分,这始终是特定于实例的。 - David Laing
是的 - 除非这违反了封装原则,否则您的另一个选择是在_create或_init方法中声明对象变量。 - alzclarke
1
静态变量通常是常量,按照惯例应该具有ALL_CAPS名称。讽刺的是,我在这个页面上看到的唯一ALL_CAPS是在这个大声回答中。 - Michael Scheper

0

看起来对于 "this" 关键字有一些误解。这个关键字使得变量成为实例特定的。请尝试下面的代码。

$.widget("ui.staticTest", {
    staticVar:'unchanged',
    test: function(a){
        if(a){
            staticVar= a;
        }
        alert(JSON.stringify(staticVar));
    }
});

$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

@alzclarke,我试过了,两次调用都返回“changed”。我有什么遗漏吗? - JS Mitrah
抱歉,你是对的!很好的想法,实际上这段代码声明并分配了一个全局变量而不是类变量。如果我在代码末尾运行alert(staticVar);,它也会弹出“changed”。同样,如果调用之前的任何代码使用了这个变量名,那么值就会丢失。 - alzclarke

0

//在小部件作用域中详细解释静态、实例和全局变量的示例

$.widget("ui.staticTest", {
    //staticVar is an instance variable, regardless of what it is named as
    staticVar: 'brownMamba',

    _create: function() {

    },

    //test the static variable
    testStatic: function(a) {
        if (a) {
        //Here you're actually creating a new static variable called 
        //staticVar which is associated with the staticTest object as you assign 
        //value to it. 
            //Lemme show you what I mean with an example
            //Here it alerts 'Undefined' as 'staticVar' does not exists
            //don't confuse it with the staticVar: 'brownMamba' declared above, 
            //that one is an instance variable
            alert("Type of $.ui.staticTest.staticVar before assignment: " + typeof $.ui.staticTest.staticVar);

            $.ui.staticTest.staticVar = a; 
            //At this point it alerts the type of 'a', which in our case is  'string'            
            alert("Type of $.ui.staticTest.staticVar after assignment: " + typeof $.ui.staticTest.staticVar);

            //value of instance variable at this point
            alert("typeof this.staticVar: " + typeof this.staticVar);
            alert("Value of this.staticVar: " +  this.staticVar);
            //value of global variable at this point
            //'Undefined' as it does not exist
            alert("Type of staticVar: " + typeof staticVar); //or window.staticVar


        } else {
            alert("value of staticVar in testStatic with no argument: " + $.ui.staticTest.staticVar);
        }
    },

    //test the instance variable
    testInstance: function(a) {
        if (a) {
        //Here you're actually working with the instance variable declared above, 
        //with the value 'brownMamba' 
        //Lemme show you what I mean with an example
        //Here it alerts 'string' as 'staticVar' exists and is assigned a string
            alert("typeof this.staticVar is " + typeof this.staticVar + " and its 
value is " + this.staticVar);

            this.staticVar = a; 
            alert("typeof this.staticVar after assignment is " + typeof this.staticVar);
            alert("Value of this.staticVar after assignment is " + this.staticVar);
        } else {
            alert("value of this.staticVar in testInstance with no argument: " + this.staticVar);
        }
    },

    //test the Global variable
    testGlobal: function(a) {
        if (a) {
        /*Here you're actually creating a global variable called staticVar*/ 
            //Lemme show you what I mean with an example
            //Here it alerts 'Undefined' as 'staticVar' does not exists
            alert("Type of staticVar before assignment: " + typeof staticVar);

            staticVar = a; //creating a global variable, which will be declared 
in window scope, i.e. window.staticVar 
            //At this point it alerts the type of a, which in our case is a 'string'            
            alert("Type staticVar after assignment: " + typeof staticVar);
            alert("Value of staticVar after assignment: " + staticVar)
        } else {
            alert("value of staticVar in testGlobal with no argument: " + staticVar);
        }
    }
});

//instantiating widget
$('#test').staticTest();
//instantiating widget
$('#parent').staticTest();

$('#test').staticTest('testStatic', 'changed');
//value will be sustained as its associated to the object
$('#parent').staticTest('testStatic');

$('#test').staticTest('testInstance', 'bluemamba');
//here the value doesn't change as its an instance variable and its value is not altered
$('#parent').staticTest('testInstance');

$('#test').staticTest('testGlobal', 'bluemamba');
//here the value is still sustained as the global is created in the previous call
$('#parent').staticTest('testGlobal');

http://jsfiddle.net/hiteshubharani/z5k4E/6/


你好,Rooster的解决方案基本上是使用全局变量,但是带有托管命名空间。因此,在构造函数中实际上不需要引用它。我已经修改了你的解决方案。 - alzclarke
alzclarke,我希望你能在我的帖子中添加自己的答案,而不是完全修改它。 - brownmamba
@brownmamba 好的,我已经撤销了我的编辑并添加了一个新答案,抱歉,没有冒犯之意! - alzclarke
@alzclarke,你的回复与我的原帖并不接近。但是,我很感激你至少尝试了,并创建了自己的帖子。谢谢。 - brownmamba
@brownmamba,我只是使用了历史下拉菜单来恢复到先前的状态,所以不确定出了什么问题...你能纠正一下吗? - alzclarke
@alzclarke 不用担心。我实际上已经升级了我的示例,并提供了详细的解释。 - brownmamba

0

Rooster的解决方案的简单实现:

$.widget("ui.staticTest", {
test: function(a){
    if(a){
        $.ui.staticTest.staticVar= a;
    }
    alert(JSON.stringify($.ui.staticTest.staticVar));
}
});
$.ui.staticTest.staticVar =  'unchanged';


$('#test').staticTest();
$('#parent').staticTest();
$('#test').staticTest('test');
$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

0
你可以使用通用的JS封装模式:
$.widget("ui.staticTest", (function() {

    staticVar:'unchanged';

    return {
        test: function(a){
            if(a){
                staticVar= a;
            }
            alert(JSON.stringify(staticVar));
        }
    };
} ()));

你的jsFiddle分支在这里:http://jsfiddle.net/pettys/RwKdZ/

优点:没有任何神奇的事情发生,在任何时候都不会干扰jQuery空间。 缺点:你的小部件缩进了另一个级别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接