克隆JavaScript对象。再次:(

时间:2009-07-22 23:14:43

标签: javascript jquery clone extend

我知道再次阅读这个话题真的很烦人。在开始挖掘代码之前,一个解决方案可能是我没有在JavaScript中获得原型和对象。但在这一点上,我认为,我做到了。

问题是:
如何克隆JavaScript类(使用原型创建),以便“克隆”类在以后扩展和执行时保持不变?

function clone(obj){
  if(obj == null || typeof(obj) != 'object')
      return obj;

  var temp = new obj.constructor();
  for(var key in obj)
      temp[key] = clone(obj[key]);

  return temp;
}

var FOO = function() {
  var myBAR = clone(BAR);
  myBAR.prototype = jQuery.extend(true, myBAR.prototype, this); // deep cloning twice and extending with this
  console.log("FOO:", this.name);
  new myBAR();
};

FOO.prototype = {
  name: "FOO"
};

var BAR = function() {
  console.log("BAR:", this.name);
};

BAR.prototype = {
  name: "BAR"
};

new FOO(); // returns FOO: FOO and BAR: FOO 
new BAR(); // returns BAR: FOO should return BAR: BAR

如果我说对了,new BAR()new FOO()之后)的第二次调用应该返回BAR: BAR而不是BAR: FOO

此问题的一个可能解决方案是完全重写clone函数,如下所示:

function clone(obj) {
  return eval("("+obj.toString()+")"); // the same as eval(uneval(obj));
}

但是这种方法有一个很大的缺点,你不能传递任何动态创建的对象。

有什么想法吗?

5 个答案:

答案 0 :(得分:1)

问题是你如何克隆'原型'

以下一行

myBAR.prototype = jQuery.extend(true, myBAR.prototype, this); // deep cloning 

您不仅要克隆'原型',还要克隆'name'属性。

如果用

替换上面的行
myBAR.prototype = jQuery.extend(true, myBAR.prototype, this.prototype); // deep cloning 

您的代码现在将返回

new FOO(); // returns FOO:FOO and BAR:BAR
new BAR(); // returns BAR:BAR

答案 1 :(得分:0)

克隆javascript对象的问题是你决定去多深?

考虑我有以下对象:

var obj = { 
    prop : {
        n1prop : {
            hello : 'world';
        }
    }
};

这意味着我必须遍历所有属于'object'类型的属性,如果你有一个深层嵌套可能会非常昂贵。

如果你有一个简单的1级对象,你可以使用简单的反射循环并创建一个新的对象文字。 注意:这不会复制原始对象的方法。

function clone(obj) {
   var cloned;

   if (obj && typeof obj === 'object') {
       cloned = {};
       for (var p in obj) {
           if (obj.hasOwnProperty(p) && typeof obj[p] !== 'function') {
               cloned[p] = obj[p]
           }
       }
       return cloned;
   }
   else {
       return null;
   }
}

答案 2 :(得分:0)

除了SolutionYogi提到的更改之外,还需要进行另一项更改。在FOO中,你要传递要克隆的BAR,但是BAR是构造函数(typeof BAR ==“function”),所以它将使第一次测试克隆函数失败,并且你的返回值将是对未更改的BAR的引用。这意味着myBAR.prototype不是BAR.prototype的克隆,而是对它的引用。

为了实际创建一个新的构造函数,而不仅仅是一个ref,我认为你将不得不使用eval - 添加如下内容:

if (typeof obj == "function) {
    eval("var temp = " + obj + ";");
    return temp;
}

还有其他注意事项(正如Alex指出的那样),但添加上述内容会导致测试用例成功。

答案 3 :(得分:0)

function clone(obj) {
    if(typeof obj !== 'undefined') {
        clone.prototype = Object(obj);
        return new clone;
    }
}

function Foo() {} // base class

function Bar() {} // derived class
Bar.prototype = clone(Foo.prototype); // inherit from `Foo.prototype`

答案 4 :(得分:0)

我只想向任何人展示我上述问题的解决方案。

function cloneClass (func) {

  if(typeof func == 'function') {

    var prototype = {};
    for (var prop in func.prototype) {
      prototype[prop] = func.prototype[prop];
    };

    var Class = function() {
      var _this = this;
      var constructor = function() {
        func.apply(_this, arguments);
      };
      constructor.prototype = _this;

      for (var property in func) {
        if(property != "prototype") {
          constructor[property] = func[property];
        }
      };

      return constructor;
    };

    Class.prototype = prototype;
    return new Class();
  }

  return func;

};

尝试深入了解它是如何工作的。有没有人能看到这个实现,内存泄漏等问题。