我想要完成的任务:使用javascript中的原型创建模块,以便用户可以使用不同的选项多次实例化模块。
问题:使用var my_module3 = new module();
然后尝试使用my_module3.init({ option: "value" });
设置选项时,每次都不会更改对象,只会更改一次。
测试:使用console.log
时,我们可以看到它打印出具有相同选项的两个对象,即使它们的设置不同
Object {first: "Barry", second: "Larry", third: "Sam"}
Object {first: "Barry", second: "Larry", third: "Sam"}
这是我的jsFiddle完整代码: http://jsfiddle.net/11bLouc8/2/
var module = (function () {
// default options
var options = {
first: "test",
second: "test2",
third: "test3"
};
// take in useroptions and replace default options
var module = function(userOptions) {
if (userOptions != null && userOptions != undefined
&& userOptions != 'undefined') {
for (var opt in options) {
if (userOptions.hasOwnProperty(opt)) {
options[ opt ] = userOptions[ opt ];
}
}
}
};
//prototype
module.prototype = {
init: module,
options: options
};
return module;
})();
// create a new instance
var my_module3 = new module();
my_module3.init({
first: "Mike",
second: "Lisa",
third: "Mary"
});
// another instance
var my_module2 = new module();
my_module2.init({
first: "Barry",
second: "Larry",
third: "Sam"
});
答案 0 :(得分:5)
函数本身的属性表现得像static
类成员(函数的属性,而不是它的实例)
function prototype
的属性在各个实例中是不同的:
function test(){};
test.prototype = {
constructor : test,
first : '',
second : '',
third : '',
init : function(f, s, t){
this.first = f;
this.second = s;
this.third = t;
return this;
},
formatToString : function(){
return 'first : ' + this.first + ', second : ' + this.second + ', third : ' + this.third;
}
}
var t1 = new test().init(1, 2, 3);
var t2 = new test().init(4, 5, 6);
console.log(t1.formatToString());//outputs "first : 1, second : 2, third : 3"
console.log(t2.formatToString());//outputs "first : 4, second : 5, third : 6"
答案 1 :(得分:4)
你正在使用一个立即调用的函数表达式(IIFE),就像Module模式所说的那样,但对于这种情况,你需要不止一次调用你的IIFE 。这涉及给它一个名字,以便你可以再次解决它,所以从技术上来说它不再是IIFE,但它的工作原理与IIFE相同。我要继续打电话了
当您调用函数时,JavaScript会为其中的变量和闭包创建一个上下文。只要IIFE之外的任何内容都引用其中的任何内容,该上下文就会存在。这就是传统模块模式使用IIFE的原因:您可以在IIFE的上下文中隐藏私有数据和函数。
但是因为您只调用该函数一次,所有模块实例共享相同的上下文。您将模块选项存储在options
变量中,这是其中的一部分共享上下文而不是成为模块的一部分,因此当您更新其中一个模块中的选项时,它会更新所有模块中的选项。有时,这就是你想要的,但不是你的情况。
您要做的是为每个模块创建一个新的上下文。这意味着您需要携带IIFE并对其进行引用,以便您可以多次调用它:换句话说,它不再是一个匿名函数(或者甚至不一定是IIFE)。但这都是可行的。这是一个可能的解决方案:
var moduleContext = function () {
// default options
var options = {
first: "test",
second: "test2",
third: "test3"
};
// take in useroptions and replace default options
var module = function(userOptions) {
if (userOptions != null && userOptions != undefined
&& userOptions != 'undefined') {
for (var opt in options) {
if (userOptions.hasOwnProperty(opt)) {
options[ opt ] = userOptions[ opt ];
}
}
}
};
//prototype
module.prototype = {
init: module,
options: options
};
return module;
};
var my_module3 = new (moduleContext())();
my_module3.init({
first: "Mike",
second: "Lisa",
third: "Mary"
});
var my_module2 = new (moduleContext())();
my_module2.init({
first: "Barry",
second: "Larry",
third: "Sam"
});
console.log(my_module2.options, my_module3.options);
魔法发生在这两条new (moduleContext())()
行中。与IIFE一样,moduleContext()
函数为模块构造函数设置上下文,然后返回它。然后new
运算符处理返回的函数,并在没有参数的情况下调用它(最后一组parens)。由于在IIFE上需要它们,所以需要围绕调用moduleContext()
的额外问题:它们解决了JavaScript解析器中的一些歧义。
现在,您的两个模块在两个不同的上下文中创建。因此,您可以在任一模块中设置“common”选项对象(就像您当前那样),但只会影响该模块上下文中的options对象。另一个没有被触及,因此您可以单独设置选项。