JavaScript 克隆对象失去了它的原型功能 [英] JavaScript cloned object loses its prototype functions

查看:88
本文介绍了JavaScript 克隆对象失去了它的原型功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 JavaScript 中克隆一个对象.我已经创建了自己的具有原型函数的类".

I am attempting to clone an object in JavaScript. I have made my own 'class' that has prototype functions.

我的问题:当我克隆一个对象时,克隆不能访问/调用任何原型函数.

My Problem: When I clone an object, the clone can't access/call any prototype functions.

当我去访问克隆的原型函数时出错:

I get an error when I go to access a prototype function of the clone:

clone.render 不是函数

clone.render is not a function

你能告诉我如何克隆一个对象并保留它的原型函数

这个简单的 JSFiddle 演示了我得到的错误:http://jsfiddle.net/VHEFb/1/

This simple JSFiddle demonstrates the error I get: http://jsfiddle.net/VHEFb/1/

function cloneObject(obj) 
{
   // Handle the 3 simple types, and null or undefined
   if (null == obj || "object" != typeof obj) return obj;

   // Handle Date
   if (obj instanceof Date) {
     var copy = new Date();
     copy.setTime(obj.getTime());
     return copy;
   }

   // Handle Array
   if (obj instanceof Array) {
     var copy = [];
     for (var i = 0, len = obj.length; i < len; ++i) {
         copy[i] = cloneObject(obj[i]);
     }
     return copy;
   }

   // Handle Object
   if (obj instanceof Object) {
     var copy = {};
     for (var attr in obj) {
         if (obj.hasOwnProperty(attr)) copy[attr] = cloneObject(obj[attr]);
     }
     return copy;
   }

   throw new Error("Unable to copy obj! Its type isn't supported.");
}

function MyObject(name)
{
    this.name = name;
    // I have arrays stored in this object also so a simple cloneNode(true) call wont copy those
    // thus the need for the function cloneObject();
}

MyObject.prototype.render = function()
{
    alert("Render executing: "+this.name);
}

var base  = new MyObject("base");
var clone = cloneObject(base);
clone.name = "clone";
base.render();
clone.render();  // Error here: "clone.render is not a function"

推荐答案

对代码的一些评论:

>    if (obj instanceof Date) {
>      var copy = new Date();
>      copy.setTime(obj.getTime());

可以是:

if (obj instanceof Date) {
  var copy = new Date(obj);

>    if (obj instanceof Array) {

如果 obj 是来自另一个全局上下文的数组,例如 iFrame,则将返回 false.考虑:

will return false if obj is an array from another global context, such as an iFrame. Consider:

     if (o && !(o.constructor.toString().indexOf("Array") == -1))

>      var copy = [];
>      for (var i = 0, len = obj.length; i < len; ++i) {
>          copy[i] = cloneObject(obj[i]);
>      }

使用slice可以更有效和准确地将一个数组的索引复制到另一个数组:

Copying the indexes of one array to another can be done more efficiently and accurately using slice:

      var copy = obj.slice();

虽然您会错过任何可能已添加的非数字属性.循环到 0 到 length 会将稀疏数组中不存在的属性添加到克隆中(例如,elisions 将成为未定义的成员).

though you will miss any other properties that might have been added that aren't numeric. Looping over 0 to length will add properties to the clone that don't exist in a sparse array (e.g. elisions will become undefined members).

至于克隆部分……

在复制对象属性部分,将所有的属性,包括原始[[Prototype]]链上的属性,直接复制到克隆"对象.真正克隆"对象的唯一方法是将其 [[Prototype]] 设置为与原始对象相同的对象,然后复制原始对象上的可枚举属性(使用 hasOwnProperty) 到克隆.

In the part copying object properties, that will copy all the properties, including those on the original's [[Prototype]] chain, directly to the "clone" object. The only way to really "clone" an object is to set its [[Prototype]] to the same object as the original, then copy the enumerable properties on the original (filtered with hasOwnProperty) to the clone.

第二部分是微不足道的,第一部分不是(一般意义上的),因为你不能保证对象的构造函数属性引用其prototype是它的[[Prototype]],也不能保证在此期间构造函数的原型没有改变(即是不同的对象).

The second part is trivial, the first part is not (in a general sense) since you can't guarantee that an object's constructor property references the object whose prototype is its [[Prototype]], nor can you guarantee that the constructor's prototype hasn't changed (i.e. is a different object) in the meantime.

最接近的是使用 Lasse Reichstein Nielsen 的 clone(由 Douglas Crockford 流行为 beget),它使原始对象成为克隆的 [[Prototype]],然后设置同一个对象的构造函数.虽然您可能仍然需要复制可枚举的自己的属性,以便它们掩盖原始的同名属性.

The closest you can get is to use Lasse Reichstein Nielsen's clone (popularised by Douglas Crockford as beget) which makes the original object the [[Prototype]] of the clone, and then set the constructor to the same object. Though you probably still need to copy over the enumerable own properties so they mask the original's same-named properties.

所以你真的只能在受限上下文中克隆一个对象,一般情况下你不能这样做.通常,这种实现会导致您不需要一般地克隆对象的设计.

So you can really only clone an object within a restricted context, you can't do it generally. And generally that realisation leads to a design where you don't need to generically clone objects.

这篇关于JavaScript 克隆对象失去了它的原型功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆