如果我在对象文字上使用Object.create()创建多个对象,我会得到多个不共享属性值的唯一对象。但是,当我在从模块返回的对象上使用Object.create()时,看起来它们共享相同的引用?这是为什么?
var objModule = (function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}());
var objModule2 = Object.create(objModule);
objModule2.setName("module 2");
console.log(objModule.getName()); // WRONG prints "module 2"
console.log(objModule2.getName()); // prints "module 2"
var objLiteral = {
name : "literal 1"
};
var objLiteral2 = Object.create(objLiteral);
objLiteral2.name = "literal 2";
console.log(objLiteral.name); // prints "literal 1"
console.log(objLiteral2.name); // prints "literal 2"
var module = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
};
var objModule1 = module();
var objModule2 = module();
objModule2.setName("module 2");
console.log(objModule1.getName()); // prints "module 1"
console.log(objModule2.getName()); // prints "module 2"
如果我像构造函数一样使用模块(由@Matt Browne建议)并创建2个对象,结果就像使用对象文字一样。我想了解的是为什么模块示例#1的行为与模块示例#3不同?
正如@ ben336解释的那样,代码:
var objModule2 = Object.create(objModule);
将objModule2的原型设置为objModule。在示例#3中不会发生这种情况,因此这两个对象不共享相同的闭包属性。
答案 0 :(得分:3)
Object.create
的第一个参数指定了正在创建的新对象的原型对象。因为在您的第一个示例中,您将现有对象设置为新对象的原型,当您调用函数时,它们正在修改您存储在闭包中的变量,然后由现有对象访问该变量。新的。
这里要理解的两个关键事项是:
此代码
var objModule = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}();
创建一个闭包,函数getName和setName保持对name
变量的访问。
这些函数是objModule的属性,当你调用Object.create
时,你将objModule设置为objModule2的原型,并且它也可以访问这些函数。
由于2个对象共享这些函数,并且它们可以访问模块创建的闭包,而不是在任一对象上本地存储name属性,因此当您使用一个对象调用set函数时,它将更新闭包,从而更新两个对象。
在第二个示例中,您还将对象设置为新对象的原型,但是您在本地对象上声明了一个覆盖原型属性的属性。
答案 1 :(得分:3)
objModule2.setName
指的是与objModule.setName
相同的功能,但具有不同的this
。 (Object.create
不复制任何内容)
调用它将设置相同的局部变量。
objLiteral2.name = "literal 2"
在objLiteral2
上创建一个新属性,该属性会隐藏继承的objLiteral.name
。
答案 2 :(得分:3)
我认为通过删除()
函数末尾的括号objModule
并将其重命名为明确它是构造函数的内容,可以更好地完成此处的操作,即改为:
var makeObjModule = function() {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}; //removed parentheses here
(就我个人而言,我个人也会使用function objModule()
语法,但这是一个单独的点,也是个人偏好的问题。)
然后你可以创建你的实例:
var objModule = makeObjModule();
var objModule2 = makeObjModule();
Object.create
方法当然也是解决这个问题的有效方法;有关制作该作品的详细信息,请参阅@ ben336的回答。
我个人认为Object.create
在继承时比在做这样的简单构造时更有用。 (有些人在使用原型继承时也更喜欢使用new
关键字,但由于你使用的是模块模式,我认为如上所示,使用“maker”/构造函数更容易。)< / p>