Object.create不使用模块模式创建新对象

时间:2013-04-21 02:06:09

标签: javascript

如果我在对象文字上使用Object.create()创建多个对象,我会得到多个不共享属性值的唯一对象。但是,当我在从模块返回的对象上使用Object.create()时,看起来它们共享相同的引用?这是为什么?

#1模块:

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"

#2 Literal:

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"

修改

#3模块“构造函数”:

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不同?

编辑2

正如@ ben336解释的那样,代码:

var objModule2 = Object.create(objModule); 

将objModule2的原型设置为objModule。在示例#3中不会发生这种情况,因此这两个对象不共享相同的闭包属性。

3 个答案:

答案 0 :(得分:3)

示例1

Object.create的第一个参数指定了正在创建的新对象的原型对象。因为在您的第一个示例中,您将现有对象设置为新对象的原型,当您调用函数时,它们正在修改您存储在闭包中的变量,然后由现有对象访问该变量。新的。

这里要理解的两个关键事项是:

  1. 此代码

    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变量的访问。

  2. 这些函数是objModule的属性,当你调用Object.create时,你将objModule设置为objModule2的原型,并且它也可以访问这些函数。

  3. 由于2个对象共享这些函数,并且它们可以访问模块创建的闭包,而不是在任一对象上本地存储name属性,因此当您使用一个对象调用set函数时,它将更新闭包,从而更新两个对象。

    示例2

    在第二个示例中,您还将对象设置为新对象的原型,但是您在本地对象上声明了一个覆盖原型属性的属性。

答案 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>