- 浏览: 1460296 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
深度复制和浅度复制 是当初初学 c 遇到的第一批问题,似乎使不少人困惑,而类 c 的 javascript 也同样存在这个问题.
第一版:
javascript 中引用类型(Object.prototype.toString.call(object))有 : Array 以及 Object , Date , RegExp ,Number, Function,Boolean .而可以修改自身的包括:
Array : 可修改自身单个元素
Object : 可修改自身单个属性
Date : 可修改自身日期,年份等
RegExp : 可修改 lastIndex
而对于基本类型的包装类型如:new Boolean() ,new Number() 虽然没有方法改变自身值,但是可能在上面附加数据,所以最好还是考虑下。
然后细心点进行深度复制:
function clone(o) { var ret = 0, isPlainObject, isArray; var constructor = o.constructor; // array or plain object if (((isArray = S.isArray(o)) || isPlainObject = S.isPlainObject(o))) { // 先把对象建立起来 if (isArray) { ret = []; } else if (isPlainObject) { ret = {}; } // clone it if (isArray) { for (var i = 0; i < o.length; i++) { ret[i] = S.clone(o[i]); } } else if (isPlainObject) { for (k in o) { if (o.hasOwnProperty(k)) { ret[k] = S.clone(o[k]); } } } } else if (typeof o=="object"&&S.inArray(constructor, [Boolean, String, Number, Date, RegExp])) { ret = new constructor(o.valueOf()); } return ret; }
第二版:
上一版虽然考虑了引用类型,但是对于一种特殊情况却会引起巨大的麻烦:循环引用时的无穷递归。例如以下数据类型:
var son={name:"x"},father:{name:"y"}; father.son=son; son.father=father; var newSon=S.clone(son);
虽然这种情况很少见,甚至不推荐。但是场景确实会存在,比如 dom 树节点就是个很好的例子.
解决:
首先要防止死循环,最常见的做法即是做标记,如果一个源已经被克隆过了,那么只需返回对应的克隆对象即可。
随后就要清除先前的标记了,又是一个问题:怎么清除?从头开始清除?那么真陷入了死循环。为了避免再次死循环就需要在第一步做标记时,把做标记的元素存起来,当最后克隆完毕,再将标记统一清除:
var CLONE_MARKER = '__cloned'; function clone(o) { var marked = {}, ret = cloneInternal(o, marked); S.each(marked, function(v) { // 清理在源对象上做的标记 v = v.o; if (v[CLONE_MARKER]) { try { delete v[CLONE_MARKER]; } catch (e) { S.log(e); v[CLONE_MARKER] = undefined; } } }); marked = undefined; return ret; } function cloneInternal(o, f, marked) { var ret = o, isArray, k, stamp; // 引用类型要先记录 if (o && ((isArray = S.isArray(o)) || S.isPlainObject(o) || S.isDate(o) || S.isRegExp(o) )) { if (o[CLONE_MARKER]) { // 对应的克隆后对象 return marked[o[CLONE_MARKER]].r; } // 做标记 o[CLONE_MARKER] = (stamp = S.guid()); // 先把对象建立起来 if (isArray) { ret = f ? S.filter(o, f) : o.concat(); } else if (S.isDate(o)) { ret = new Date(+o); } else if (S.isRegExp(o)) { ret = new RegExp(o); } else { ret = {}; } // 存储源对象以及克隆后的对象 marked[stamp] = {r:ret,o:o}; } // array or plain object need to be copied recursively if (o && (isArray || S.isPlainObject(o))) { // clone it if (isArray) { for (var i = 0; i < ret.length; i++) { ret[i] = cloneInternal(ret[i], f, marked); } } else { for (k in o) { if (k !== CLONE_MARKER && o.hasOwnProperty(k) && (!f || (f.call(o, o[k], k, o) !== false))) { ret[k] = cloneInternal(o[k], f, marked); } } } } return ret; }
可以找个复杂的例子验证下:
var t7 = [], t8 = {x:1,z:t7}, t9 = {y:1,z:t7}; t7.push(t8, t9);
画个图就是:
那么 clone=S.clone(t7) 的结果应该和 t7 内容一样并且包含关系完全相同即:
不足:
该算法只适用于配置参数等简单数据类型克隆,对于具备复杂原型链的自定义对象尚不能很好支持,或许可以通过
ret=new o.constructor()
来生成对应类型对象,但是由于执行了构造器或存在副作用.
Refer:
原来已经有规范了,不过如果出现 HTMLNode function 就报错的做法不妥?:
发表评论
-
continuation, cps
2013-09-12 16:49 2791起 随着 nodejs 的兴起,异步编程成为一种潮流 ... -
一种基于匹配回朔的 css3 选择器引擎实现
2013-05-07 20:40 3401一种基于匹配回朔的 css3 选择器引擎实现 介绍 C ... -
cubic-bezier 模拟实现
2013-01-05 16:34 14089cubic-bezier 曲线是 css3 动画的一个重要基石 ... -
构建前端 DSL
2012-10-11 22:10 5359目前在传统的软件开 ... -
Get cursor position and coordinates from textarea
2012-04-10 20:50 5037最近需要从 textarea 中获 ... -
兼容 ie 的 transform
2012-02-23 14:00 6424css 2d transform 是 css3 引入的一个新的 ... -
promise api 与应用场景
2012-02-07 17:34 7375promise 是 commonjs 社区中提出的异步规范,其 ... -
closure compiler 代码优化实例
2012-01-08 03:23 2829closure compiler 可以进行不少有意思的优化 ... -
circular dependency
2011-12-11 18:23 3922循环依赖是和语言无关 ... -
write html parser
2011-12-01 02:48 2916首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取 ... -
获取剪贴板数据
2011-11-07 23:31 6447兼容性: 获取剪贴板数据这块各个浏览器间存在很大的 ... -
url 映射问题
2011-11-07 21:52 3221背景 url mapping 我最早知道是作为 j ... -
tip:如何原生播放声音
2011-10-19 12:45 2977如果不想考虑浏览器间 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2845简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2845场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2268分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 7047作为前端开放的基础安全保证,caja 是目前比较合 ... -
tokenization of html
2011-08-29 22:38 2786html 符号解析问题 场景: 在页面上输出包 ... -
ie 下 cloneNode 导致的属性克隆
2011-08-24 16:10 2475这个还是很值得记下,一直存在的很大隐患终于解决,由于在 ie& ... -
模块的静态与动态循环依赖
2011-07-25 03:43 3279场景: 循环依赖 我是不支持的,但现实中似乎又确实需 ...
相关推荐
2. **手工编写方式**:对于复杂对象或者包含大量循环引用的对象,可以通过重写对象中的`clone()`方法并手动处理其中的引用类型成员变量来实现深度克隆。这种方式更加灵活,但编写起来相对复杂且容易出错。 #### 三...
这种方法简单易用,但不适用于包含函数或循环引用的对象,因为它不能处理函数和会丢失原型链信息。 ### Python中的深度克隆 Python的`copy`模块提供了`deepcopy()`函数,可以方便地实现深度克隆: ```python ...
此外,还可以利用JSON序列化和反序列化实现深度克隆,但这种方法有一些限制,例如不能处理函数和循环引用。 ```javascript function deepClone(origin, target, hash = new WeakMap()) { if (origin === null) ...
4. **性能优化**:对于大型或循环引用的对象,深度克隆函数需要有良好的性能表现,避免无限递归和内存消耗过大。 5. **可配置性**:允许设置参数来定制克隆行为,例如忽略某些属性、处理特定类型的数据等。 总之,...
需要注意的是,深度克隆并不是JavaScript的标准功能,而是通过各种技术手段实现的,因此在处理复杂数据结构时可能会遇到问题,如循环引用、函数、日期、正则表达式等非标准JSON格式的对象。此外,性能也是一个考虑...
深度克隆对象,支持循环引用和属性描述符 var clone = require ( '@dmail/object-clone' ) ; var a = { name : 'a' } ; var b = clone ( a ) ; b . name ; // 'a' // of course b != a 它克隆得很深 var a = { ...
这样可以实现深度克隆,但需要注意的是,这种方法不适用于包含函数、循环引用、`undefined`等非JSON兼容类型的对象。 ```javascript var scheduleClone2 = JSON.parse(JSON.stringify(schedule)); ``` 虽然这种...
omniclone用于对象深度克隆的同构和可配置的javascript函数。 omniclone(来源[,配置,[,访问者]]); 例如:const obj = {foo:{bar:'baz'}}; const obj2 = omniclone(obj); obj2; // {omniclone用于...
需要注意的是,这种方法仅适用于"纯数据"的JSON对象,即对象中没有包含函数、循环引用或其他非JSON兼容类型。如果对象中包含函数、日期对象、正则表达式或者其他不能直接转换为JSON的值,`JSON.stringify()`会忽略...
标题提到的"nanoclone"是一个极简的JavaScript库,其核心代码只有145字节,但能实现深度克隆功能。这在追求轻量级解决方案的场景下显得尤为宝贵。 在JavaScript中,有多种实现深拷贝的方法。例如,可以使用JSON的...
例如,当你想要创建一个用户配置对象的副本,以便在不改变用户原始设置的情况下进行操作,或者在处理复杂数据结构时,确保不会污染原始数据,深度克隆就显得尤为重要。 在提供的代码示例中,展示了如何手动实现一个...
JavaScript中的对象克隆,主要是指复制一个对象,得到一个新的对象,这个新对象具有与原对象...对于复杂的对象或数组,尤其是在对象中存在嵌套循环引用的情况下,可能需要专门的库或更为复杂的递归函数来实现深度克隆。
JavaScript深度克隆是一种在编程中复制对象或数组的方式,它不仅复制了对象的表面属性,还复制了嵌套的对象和数组。在JavaScript中,浅拷贝(shallow copy)只复制对象的引用,而深度克隆(deep clone)会创建一个...
这种方法简单快捷,但需要引入Newtonsoft.Json库,且不能处理非序列化的成员或循环引用。 ```csharp public static List<T> Clone(this List<T> list) where T : new() { var str = JsonConvert.SerializeObject...
但是,这种方法不能处理函数、循环引用以及Date、RegExp等特殊类型的对象。 2. 循环遍历:通过递归地遍历对象的所有属性,创建一个新的对象并逐个复制属性。这可以处理更复杂的情况,包括嵌套的对象和数组,但性能...
- 在深度克隆或拷贝对象时,确保不会因为循环引用导致栈溢出或内存消耗过大。 - 在进行JSON.stringify()操作前,检查并打断循环引用,防止报错。 - 在数据传输或存储前,确保数据结构无循环引用,提高数据处理...