【问题标题】:new vs object create giving different results OO javascriptnew vs object create 给出不同的结果 OO javascript
【发布时间】:2014-01-23 07:43:59
【问题描述】:

我正在处理一个点亮的数据对象,然后尝试创建一个新对象,仅针对该实例更改数据属性中的属性,这是来自 jsbin 的一些测试代码

data = {
  innerData : 1 
}

-------------

'This works :-)'

construct = function(d){
  this.data = Object.create(d);
};

construct.prototype.c = function(n){
  this.data.innerData  =  n;
};

construct.prototype.d = function(){
   console.log(this.data.innerData)
};

--------------

'This does not :-{'

construct = {
  data : Object.create(data),
  changeData : function(n){
    this.data.innerData  =  n;
  },
  showData:function(){
    console.log(this.data.innerData)
  }
}

--------------

newInst = Object.create(construct);
newInst.changeData(5);
newInst.showData();

newInst2 = Object.create(construct);
newInst2showData();

当我使用构造函数/原型函数运行它时,它可以工作并且控制台输出 5,2

当我使用对象文字运行它时,控制台输出 5,5 我猜当我创建第一个实例时,它会更改实际数据对象,而不是构造对象实例的数据属性。

如果有人能深入解释为什么会发生这种情况,那将会很有帮助,因为我已经很久没有使用 OOJS了

更新:

所以我尝试了合并我从答案中发现有用的内容,我想出了这个....

data = {
  innerData : 1 
}

function construct(d){
  return {
    data : Object.create(d),
    changeData : function(n){
      this.data.innerData  =  n;
    },
    showData : function(){
      console.log(this.data.innerData)
    }
  }
}

build = function(){
 return(new construct(data));
}

newInst = build();
newInst.changeData(5);
newInst.showData();

newInst2 = build();
newInst2.showData();

【问题讨论】:

  • 数组通过引用传递而不是复制。
  • @zerkms 什么数组? :)
  • @Jack:哎呀,对象。谁重要

标签: javascript oop constructor object-literal


【解决方案1】:

这看起来像是在尝试创建工厂函数而不是构造函数。由于Object.create 现在很普遍,并且在不可用的情况下可用于这些目的,这可能已成为最佳默认值,尽管仍有大量构造函数。

其他一些答案解释了您的尝试出了什么问题。以下是您可以执行的操作,以使其按预期工作:

var factory = (function() {
  var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
  var data = {
    innerData : 1 
  };

  var proto = {
    changeData : function(n){
      this.data.innerData = n;
    },
    showData:function(){
      console.log(this.data.innerData)
    }
  };

  return function() {
    var obj = Object.create(proto);
    obj.data = clone(data);
    return obj;
  }
}());

但看起来你的innerData 可能是一个尝试让这些东西发挥作用的实验。没必要,这样会更干净:

var factory = (function() {
  var proto = {
    data: 1,
    changeData : function(n){
      this.data = n;
    },
    showData:function(){
      console.log(this.data)
    }
  };

  return function() {
    return Object.create(proto);
  }
}());

【讨论】:

  • 您的克隆方法假定存在 JavaScript 对象 的标准 JSON 表示,但实际情况可能并非如此。
  • 不幸的是,我需要 IE7 支持,这意味着添加另一个文件 :-(,我确实尝试了一种最初在 IE7 中有效的不同克隆方法。不过,我确实喜欢你的想法
  • @PaulS.:是的,这个clone 完全是幼稚的,主要是因为我希望它可以被完全丢弃以支持第二个版本。
  • @OliMillington:我希望类似于第二个版本的东西会更有帮助,但很可能您的 data 对象太复杂了。
【解决方案2】:

鉴于我们对继承的了解,以下实际做了什么

this.data.innerData  =  n;

其中thisObject.create(construct) 的结果?

  1. this 没有自己的属性data,所以在继承的属性中查找。
  2. 好的,我们找到了data === Object.getPrototypeOf(this).data,就叫它d
  3. 下一组d 中的innerDatan

所以实际结果是 innerData 属性已设置在 prototype 的引用上,而不是新的 Object

为什么会这样?因为如果你有o = {} 并尝试做o.foo.bar,你会得到一个TypeError: Cannot read property 'bar' of undefined,因此为了不抛出错误,它必须访问一个定义的对象。 p>

var proto = {foo: {bar: 'fizz'}},
    obj = Object.create(proto);
obj.foo.bar = 'buzz';
proto.foo.bar; // "buzz" (i.e. NOT "fizz" anymore)
// and
obj.foo === Object.getPrototypeOf(obj).foo; // true

【讨论】:

    【解决方案3】:

    在第二个示例中,只有一个 data 对象。该对象位于construct 中,并且可用于原型链上的所有后续对象。

    在您的第一个示例中,每次创建新实例时都会创建一个新的 data 对象。所以每个对象都有自己的data 副本。

    试试这个,第一个例子:

    console.log(newInst.data === newInst2.data); // should be false
    

    第二个例子:

    console.log(newInst.data === newInst2.data); // should be true
    

    【讨论】:

    • 那么在第二个例子中没有办法制作新的数据副本吗?
    • 是的,有几种方法。最方便的方法可能是使用构造函数,这是您的第一个示例使用的。您还可以创建一个吐出新对象的工厂函数。
    • 好的,我明白了,我原以为它在这些方面的某个地方,但无法完全弄清楚,并认为我不需要构造函数。
    【解决方案4】:

    第二段代码运行良好:

    construct.changeData(2);
    construct.showData(); // 2
    

    唯一的区别是在上面的例子中construct不是一个构造函数,所以与第一种方法相反,construct.data只有一个实例;在其上调用Object.create() 将创建一个新对象,但将保持与第一个相同的.data 引用。

    【讨论】:

    • 感谢您的回答。马特直接说得更有意义了,但是 +1
    猜你喜欢
    • 2011-10-22
    • 2021-10-30
    • 1970-01-01
    • 2014-02-28
    • 2023-04-08
    • 1970-01-01
    • 2018-06-04
    • 2018-08-30
    • 1970-01-01
    相关资源
    最近更新 更多