1

我知道再次阅读这个话题真的很烦人。在开始深入研究代码之前,一种解决方案可能是我没有在 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()(after new FOO()) 的第二次调用应该BAR: BAR不会BAR: FOO像现在那样返回。

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

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

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

有任何想法吗?

4

5 回答 5

1

问题是你如何克隆“原型”

以下行

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

您不仅克隆了“原型”,还克隆了“名称”属性。

如果将上面的行替换为

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

您的代码现在将返回

new FOO(); // returns FOO:FOO and BAR:BAR
new BAR(); // returns BAR:BAR
于 2009-07-23T02:39:24.060 回答
0

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

考虑我有以下对象:

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

这意味着我将不得不遍历所有类型为“对象”的属性,如果您有深层嵌套,这可能会变得非常昂贵。

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

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;
   }
}
于 2009-07-23T01:30:51.270 回答
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 指出的那样),但添加上述内容应该会导致您的测试用例成功。

于 2009-07-23T04:57:17.663 回答
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`
于 2009-07-23T06:47:19.423 回答
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;

};

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

于 2009-07-27T18:36:47.677 回答