Javascript cloned object looses its prototype functions
我正在尝试用JavaScript克隆一个对象。我已经创建了自己的具有原型函数的"类"。
我的问题是:当我克隆一个对象时,克隆无法访问/调用任何原型函数。
我在访问克隆的原型函数时出错:
clone.render is not a function
你能告诉我如何克隆一个对象并保留它的原型函数吗
这个简单的jsfidle演示了我得到的错误:http://jsfidle.net/vhefb/1/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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" |
对代码的一些注释:
1 2 3 | > if (obj instanceof Date) { > var copy = new Date(); > copy.setTime(obj.getTime()); |
可以是:
1 2 | if (obj instanceof Date) { var copy = new Date(obj); |
和
1 | > if (obj instanceof Array) { |
如果obj是来自另一个全局上下文(如iframe)的数组,则返回false。考虑:
1 2 3 4 5 6 | 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]); > } |
使用
1 | var copy = obj.slice(); |
尽管您会错过任何其他可能添加的非数字属性。循环长度超过0将向稀疏数组中不存在的克隆添加属性(例如,省略将成为未定义的成员)。
至于克隆部分…
在复制对象属性的部分中,将所有属性(包括原始的
第二部分是琐碎的,第一部分不是(一般意义上),因为你不能保证一个对象的构造函数属性引用了
最接近的方法是使用lasse reichstein-nielsen的
因此,您实际上只能在受限制的上下文中克隆一个对象,一般情况下不能这样做。通常,实现会导致一种设计,在这种设计中,您不需要一般地克隆对象。
您的功能可以简化为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | function cloneObject(obj) { obj = obj && obj instanceof Object ? obj : ''; // Handle Date (return new Date object with old value) if (obj instanceof Date) { return new Date(obj); } // Handle Array (return a full slice of the array) if (obj instanceof Array) { return obj.slice(); } // Handle Object if (obj instanceof Object) { var copy = new obj.constructor(); for (var attr in obj) { if (obj.hasOwnProperty(attr)){ if (obj[attr] instanceof Object){ copy[attr] = cloneObject(obj[attr]); } else { copy[attr] = obj[attr]; } } } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } |
这是一把正在工作的J小提琴
而不是
1 | var copy = {}; |
使用
1 | var copy = new obj.constructor; |
我将使用要克隆的对象的构造函数来实例克隆对象:
1 | var copy = {}; |
将
1 | var copy = new obj.constructor(); |
这是一个快速的响应,我没有考虑过这种解决方案的缺点(我考虑的是重型构造函数),但是,乍一看,它应该是有效的(我不会提到(或求助于)像
更新:
你应该求助于
1 | var copy = {}; |
将
1 | var copy = Object.create(obj.constructor.prototype); |
这样,就不会调用原始的构造函数来创建对象(考虑一个执行长时间Ajax调用以从服务器检索数据的构造函数),因为object.create等效于
1 2 3 4 5 | Object.create = function (proto) { function F() {} F.prototype = proto; return new F(); }; |
如果您使用的javascript引擎不支持此功能(它被添加到ecmascript 5规范中),则可以使用此代码。