克隆 JavaScript 对象。 再次 :(

发布于 2024-07-27 13:45:41 字数 1211 浏览 7 评论 0原文

我知道再次阅读这个话题真的很烦人。 在开始深入研究代码之前,一种解决方案可能是我没有在 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));
}

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

有任何想法吗?

I know it is really annoying to read this topic again. Before you start diggin into the code, one solution could be that I don't get prototypes and objects in JavaScript. But at this point i think, i do.

The problem is:
How to clone an JavaScript Class (created with prototypes), so that the “cloned” Class remains untouched when extending and executing afterwards?

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

If i've got it right, the second call of new BAR() (after new FOO()) should return BAR: BAR not BAR: FOO as at the moment.

One possible solution for this problem is an complete rewrite of the clone function in something like this:

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

But this approach has an BIG downside, you can't pass any dynamically created objects.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情场扛把子 2024-08-03 13:45:42

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

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;

};

尝试深入研究它以了解其工作原理。 有谁能看到这个实现的任何问题,内存泄漏等?

I just wanted to show anyone my solution for the problem above.

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;

};

Try to dig into it to understand how this is working. Does anyone can see any problems with this implementation, memory leaks etc.?

旧瑾黎汐 2024-08-03 13:45:41

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

以下行

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

The problem is how you are cloning the 'prototype'

The following line

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

You are not only cloning the 'prototype', you are also cloning the 'name' property.

If you replace above line with

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

Your code will now return

new FOO(); // returns FOO:FOO and BAR:BAR
new BAR(); // returns BAR:BAR
合约呢 2024-08-03 13:45:41

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

The issue with cloning a javascript object is how deep do you decide to go?

Consider i have the following object:

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

This means i would have to traverse all properties that are of type 'object' which could get quite expensive if you have a deep nesting.

If you have a simple 1 level object you could just use a simple reflection for loop and create a new object literal.
NOTE: This won't copy methods of the original object.

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;
   }
}
听风念你 2024-08-03 13:45:41

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

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

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

还有其他考虑因素(正如亚历克斯指出的),但添加上述内容应该会导致您的测试用例获得成功。

There is an another change that needs to be made, in addition to that mentioned by SolutionYogi. In FOO, you're passing BAR to be cloned, but BAR is constructor (typeof BAR == "function"), so it's going to fail the first test the clone function, and your return value will be a reference to an unchanged BAR. And that means myBAR.prototype is not a clone of BAR.prototype, but a reference to it.

In order to actually create a new constructor, not just a ref, I think you'll have to use eval--adding something like:

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

There are other considerations (as Alex points out), but adding the above, should cause your test case to be successful.

海未深 2024-08-03 13:45:41
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 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`
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文