【问题标题】:JavaScript cloning a "class" instance [duplicate]JavaScript克隆“类”实例[重复]
【发布时间】:2024-01-08 03:56:01
【问题描述】:

我有一堂课是这样的:

function Element(){
    this.changes = {};
}

现在我有一个这样的“类”实例,el = new Element()。这些实例存储在一个数组中,例如elements.push(el)

这个元素数组现在存储在一个对象中,然后将其推入一个数组states

现在在某些情况下我需要其中一个元素的副本,因此我需要执行类似var cloned = $.extend(true, {}, states[0]) 的操作。这里我假设我们正在克隆第一个状态。

现在的问题是我得到的 state[1].elements[0] 仍然指向原始实例。因此,我对克隆对象所做的任何更改都会更改原始对象。

卡在这样一个小问题上真是令人沮丧……

这是我为测试它而创建的小提琴: http://jsfiddle.net/E6wLW/

【问题讨论】:

  • 我似乎无法复制这个,看看这个jsFiddle
  • 我刚刚添加了一个指向 jsfiddle sn-p 的链接
  • 另外,我对问题做了一些修改
  • 正确的解决方案是重新设计算法以消除对深度复制的需求。深度复制是a)正确的噩梦,b)计算成本高,c)创建依赖于所有被深度复制的逻辑。深拷贝是一个难以解决的问题,应该通过使用浅拷贝来避免。

标签: javascript jquery object clone extend


【解决方案1】:

$.extend 只是克隆普通对象。如果对象有构造函数,那么它不会被克隆,而只是被复制。

来自$.extend 来源:

if ( jQuery.isPlainObject(copy) /* ... */) {
  // do the recursive $.extend call and clone the object                
} else if ( copy !== undefined ) {
  target[ name ] = copy;
  // ^^^^^ just copy
}

所以$.extend() 将调用isPlainObject(el),这将返回false,因为el 有一个构造函数,而不是克隆el 被复制。所以states[1].elements[0]states[0].elements[0] 是同一个对象,因为它没有被克隆。

如果我们修改您的示例:

function Element(){
  this.changes = {};
}
var el = new Element();    // $.isPlainObject(el); <- false
// ...

进入:

var el = { changes: {} };  // $.isPlainObject(el); <- true
// ...

它将正确克隆el。看到它HERE

【讨论】:

  • 所以基本上jQuery的extend方法很傻。
  • @Raynos $.extend() 无法完全支持带有构造函数的对象,因为它不知道要使用什么参数。
  • 使用什么参数无关紧要。他们需要做的就是一对一地复制对象属性。这很容易做到。
  • @Raynos 这并不是您需要做的全部,因为您拥有对象的所有属性,但原型不正确,它远非“克隆”。还是我错过了什么:)?
  • clone。忽略你必须做的大量边缘情况和黑魔法,克隆功能的核心真的很容易。主要问题区域是宿主对象和具有内部魔法的本地对象。哦,避免在深拷贝中循环引用。
【解决方案2】:

您可以使用http://documentcloud.github.com/underscore/#clone 克隆对象,例如:

var cloned = _.clone(states[0]);

【讨论】:

  • 这行不通。阅读您发布的链接:Any nested objects or arrays will be copied by reference, not duplicated.