克隆JavaScript对象。再次:(

克隆JavaScript对象。再次:(,javascript,jquery,clone,extend,Javascript,Jquery,Clone,Extend,我知道再次阅读这个主题真的很烦人。在你开始深入研究代码之前,一个解决方案可能是我没有JavaScript中的原型和对象。但在这一点上,我认为,我有 问题是: 如何克隆JavaScript类(使用原型创建),以便“克隆”的类在以后扩展和执行时保持不变? function clone(obj){ if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); f

我知道再次阅读这个主题真的很烦人。在你开始深入研究代码之前,一个解决方案可能是我没有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
如果我答对了,第二次调用
newbar()
(在
newfoo()
之后)应该返回
BAR:BAR
而不是
BAR:FOO

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

function clone(obj) {
  return eval("("+obj.toString()+")"); // the same as eval(uneval(obj));
}
但是这种方法有一个很大的缺点,即不能传递任何动态创建的对象


有什么想法吗?

克隆一个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;
   }
}

克隆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;
   }
}

问题在于如何克隆“原型”

下一行

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

问题在于如何克隆“原型”

下一行

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

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

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

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

还有其他注意事项(正如Alex指出的),但是添加上述内容应该会使您的测试用例成功。

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

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`
为了实际创建一个新的构造函数,而不仅仅是一个ref,我认为您必须使用eval——添加如下内容:

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

还有其他注意事项(正如Alex指出的),但是添加上述内容应该会使您的测试用例成功。

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

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`
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;

};

试着深入了解它是如何工作的。是否有人能看到此实现存在任何问题、内存泄漏等?

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

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;

};

尝试深入了解它是如何工作的。是否有人可以看到此实现存在任何问题、内存泄漏等?

此原型是我的案例,是一个未定义的属性,因为对象已经创建。我不记得此.prototype属性可能存在于初始化的“类”中.如果您想从已初始化的“类”获取原型您必须改用arguments.callee.prototype。因此,您使用的是静态对象的原型,而不是当前的动态对象。此原型在我的案例中是一个未定义的属性,因为对象已经创建。我不记得此.prototype属性可能存在于初始化的“类”中.如果您想从已初始化的“类”获取原型您必须使用arguments.callee.prototype。因此,您使用的是静态对象的原型,而不是当前的动态对象。对不起,Alex,这并没有解决我在动态创建对象方面的问题。您的方法与我的克隆函数非常类似。对不起,Alex,这并没有解决我在动态对象方面的问题您的方法与我的克隆函数非常相似。是的,这对静态对象很好,但对动态对象不起作用。假设您在其中有一个对DOM元素的引用。您认为需要BAR(构造函数)的情况是什么有对DOM对象的引用?是的,这对静态对象很好,但对动态对象不起作用。假设您在其中有对DOM元素的引用。您认为什么情况会导致BAR(构造函数)有对DOM对象的引用?您所说的“动态创建的对象”是什么意思?假设您在
FOO
中创建了
CAT
的实例,并将CAT保存为属性,如
this.CAT=new CAT();
CAT
类创建并保存了对DOM元素的引用。如
this.myBody=$(“body”)
。在克隆过程中,您希望何时复制,何时复制引用?根据您的评论,您的示例代码似乎没有反映您试图解决的问题