EcmaScript对象克隆之谜
先谈谈深拷贝
如何在js中获得一个克隆对象,可以说是喜闻乐见的话题了。相信大家都了解引用类型与基本类型,也都知道有种叫做深拷贝的东西,传说深拷贝可以获得一个克隆对象!那么像我这样的萌新自然就去学习了一波,我们能找到的代码基本都是这样的:
低配版深拷贝
1 |
var deepClone = function(currobj){
|
啧啧真是很精巧啊!对于Array和普通Object都做了区分。但是显然,借助递归实现的深拷贝如果要克隆层级很多的复杂对象,容易造成内存溢出,咱可以做出一个小小改进:
看起来酷一点的深拷贝
1 |
var deepClone = function(currobj){
|
这里利用了两个队列,还算优雅的避免了递归的弊端。
JSON序列化
还有一种方法是利用JSON的内置方法,即所谓的JSON序列化:
1 |
var deepClone = function(obj){
|
不过不打紧,它与上面方法的效果基本相同。
上面几种深拷贝的局限
拜托,大家都很懂对象,上面的方法有几个很大的问题:
- 遇到对象内部的循环引用直接gg
- 无法拷贝函数(typeof 函数 得到的是 ‘function’),函数仍是引用类型
- 无法正确保留实例对象的原型
于是,我们就要开始改造上面的深拷贝方法来进行完美的克隆了!………….么?
等下,你到底要啥
克隆克隆,我们平常把它挂在嘴上,但面对一个对象,我们真正想克隆的是什么?我想在99%的情况下,我们想克隆的是对象的数据,而保留它的原型引用和方法引用,因此上面提到的局限中的第二点,基本可以不考虑。现在咱再来看看怎么解决剩下两点。
解决循环引用
首先搞清什么是循环引用,常见的循环引用有两种:
自身循环引用
1 |
var a = {};
|
这种循环引用可以说很是常见。
多个对象互相引用
1 |
var a = {};
|
也不是没见过,不过这是典型导致对象内存无法被回收的写法,本身就不推荐。
解决之道
目前只找到了针对第一种引用的解决方法,来自于Jquery源码:
1 |
jQuery.extend = jQuery.fn.extend = function() {
|
解决原型的引用
在我们想办法魔改深拷贝时,先看下以上这么多深拷贝的基本原理:
利用for-in循环遍历对象属性,如果属性值是对象则深拷贝,不是则直接赋值
于是俺眉头一皱发现事情并不简单,俺上一篇博客已经说明:for-in遍历的是对象以及其原型链上可枚举属性,因此想在遍历时对源对象的__proto__做手脚是根本不存在的,__proto__以及它的不可枚举属性根本不会被遍历到。可以通过下面的例子看出:
1 |
var deepClone = function() {...} // 随便从上面拿一个
|
因此,一个解决方法很单纯,就是像上面的jQuery.extend方法一样,自己传入拷贝的目标对象,extend方法本质上只是拓展目标对象的属性,使其获得源对象上的数据,这样一来只要我们先创建好符合需求的目标对象即可。
另一种方法则是不采用深拷贝,直接取出需要进行拷贝的对象的数据,然后再利用这份数据来实例化和设置一个新的对象出来:
1 |
var Foo = function( obj ){
|
问题同样得到解决【鼓掌】
回顾一下,没有哪种方法是万用的魔法 —— 在我们想要获得一个克隆对象之前,或许最好先搞清楚我们到底是在克隆什么,再采用最适合的方法。而非是拘泥于“深拷贝浅拷贝”的说法,去复制一段代码祈祷他能生效。我相信以上的示例代码还没有考虑到克隆对象的所有问题,但它们在合适的场景下能够处理合适的问题。嗯,其实很多事情都是这样蛤【带!】
EcmaScript对象克隆之谜的更多相关文章
- Java提高篇——对象克隆(复制)
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- C#对象克隆介绍
浅拷贝和深拷贝 有两种对象克隆的方法:浅拷贝和深拷贝.浅拷贝只是复制引用,而不会复制引用的对象.深拷贝会复制引用的对象. 因此,原始对象中的引用和浅拷贝对象中的同一个引用都指向同一个对象.而深拷贝的对 ...
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
- js对象克隆, 深复制.
亲测有效: //对象克隆 function clone(obj) { // Handle the 3 simple types, and null or undefined if (null == o ...
- (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- 【java】对象克隆protected Object clone() throws CloneNotSupportedException
package 对象克隆; class A implements Cloneable{//要具备clone()功能必须要实现Cloneable接口,此接口里无方法,只起标识作用. private St ...
- java 浅拷贝和深拷贝 对象克隆clone
分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...
- js对象克隆
大家都知道,js的对象是引用类型,如果直接var obj2 = obj,obj2和obj是共享同一个对象实体的,这往往不是我们想要的结果. 官方并没有给出通用的对象克隆方法: 我们给出以下几种写法: ...
随机推荐
- OAF_OAF Framework学习笔记的基本概念(概念)
2014-11-02 Created By BaoXinjian
- c#的SortedList使用方法
表示键/值对的集合,这些键和值按键排序并可按照键和索引访问. SortedList最合适对一列健/值对 进行排序,在排序时,是对键进行排序,SortedList 是 Hashtable 和 Array ...
- 以太网帧格式、IP数据报格式、TCP段格式+UDP段格式 详解
转载:http://www.cnblogs.com/lifan3a/articles/6649970.html 以太网帧格式.IP数据报格式.TCP段格式+UDP段格式 详解 1.ISO开放系统有 ...
- 关于VS中的调试信息输出
有时候一些项目的调试信息不方便输出到界面中,比如ASP.NET或者WPF之类的 可以使用Debug.WriteLine()等方法输出到"输出"窗口,不过"输出" ...
- OpenWrt加入iptables 支持过滤字符串
须要在iptables命令选项中选择mod filter Network->Firewall->iptables->mod filter Kernel Modules->Net ...
- unity3D角色代码控制问题
///////////////2015/07/06//////// ///////////////by xbw////////////// //////////////环境 unity4.6.1// ...
- QWidget子窗口中setStyleSheet无效,解决方法
继承 QWidget setStyleSheet无效,解决方法. 发现 继承自QWidget的自定义类 ,使用setStyleSheet无效, 如果删除头文件中的 Q_OBJECT,setStyleS ...
- 批处理学习笔记2 - 编写批处理的for循环
批处理中的for循环集成的功能比较多,可以直接对文件操作. ====================================================================== ...
- ISE联合modelsim功能仿真和综合后仿真
1.代码输入 (1).新建一个ISE工程,名字为count4. (2).新建一个verilog文件 (3).选择verilog module 输入file name为count4,单击next默认知道 ...
- 基于Nginx实现10万+并发,你应该做的Linux内核优化
由于默认的linux内核参数考虑的是最通用场景,这明显不符合用于支持高并发访问的Web服务器的定义,所以需要修改Linux内核参数,是的Nginx可以拥有更高的性能: 在优化内核时,可以做的事情很多, ...