- 浏览: 1431414 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
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 2710起 随着 nodejs 的兴起,异步编程成为一种潮流 ... -
一种基于匹配回朔的 css3 选择器引擎实现
2013-05-07 20:40 3339一种基于匹配回朔的 css3 选择器引擎实现 介绍 C ... -
cubic-bezier 模拟实现
2013-01-05 16:34 14008cubic-bezier 曲线是 css3 动画的一个重要基石 ... -
构建前端 DSL
2012-10-11 22:10 5277目前在传统的软件开 ... -
Get cursor position and coordinates from textarea
2012-04-10 20:50 4920最近需要从 textarea 中获 ... -
兼容 ie 的 transform
2012-02-23 14:00 6327css 2d transform 是 css3 引入的一个新的 ... -
promise api 与应用场景
2012-02-07 17:34 7275promise 是 commonjs 社区中提出的异步规范,其 ... -
closure compiler 代码优化实例
2012-01-08 03:23 2763closure compiler 可以进行不少有意思的优化 ... -
circular dependency
2011-12-11 18:23 3842循环依赖是和语言无关 ... -
write html parser
2011-12-01 02:48 2842首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取 ... -
获取剪贴板数据
2011-11-07 23:31 6370兼容性: 获取剪贴板数据这块各个浏览器间存在很大的 ... -
url 映射问题
2011-11-07 21:52 3156背景 url mapping 我最早知道是作为 j ... -
tip:如何原生播放声音
2011-10-19 12:45 2883如果不想考虑浏览器间 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2780简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2782场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2194分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 6925作为前端开放的基础安全保证,caja 是目前比较合 ... -
tokenization of html
2011-08-29 22:38 2668html 符号解析问题 场景: 在页面上输出包 ... -
ie 下 cloneNode 导致的属性克隆
2011-08-24 16:10 2405这个还是很值得记下,一直存在的很大隐患终于解决,由于在 ie& ... -
模块的静态与动态循环依赖
2011-07-25 03:43 3184场景: 循环依赖 我是不支持的,但现实中似乎又确实需 ...
相关推荐
输入表达式列表,进行扫描,将带有子表达式引用的复合表达式分解成原子表达式,同时进行循环引用的检查。 以下为使用方法 int main(){ std::map, TOPS> Exps; std::map, TResult> Results; std::map, TOPS> ...
分析关于block的循环引用 详细了分析在ios开发中常见的错误,值得一看
iOS中的timer的循环引用问题,对timer进行了一次封装
深度克隆对象,支持循环引用和属性描述符 var clone = require ( '@dmail/object-clone' ) ; var a = { name : 'a' } ; var b = clone ( a ) ; b . name ; // 'a' // of course b != a 它克隆得很深 var a = { ...
通过Runtime监测循环引用(Facebook出品).zip,帮助检测运行时保留周期的ios库。
omniclone用于对象深度克隆的同构和可配置的javascript函数。 omniclone(来源[,配置,[,访问者]]); 例如:const obj = {foo:{bar:'baz'}}; const obj2 = omniclone(obj); obj2; // {omniclone用于...
block引用,解决办法,方便简单
在Java开发中,循环引用是指两个或多个对象相互引用,导致无法被垃圾回收器回收,从而引发内存泄漏的问题。这种问题在大型应用程序中经常会出现,因此解决循环引用问题是非常重要的。 例子及解决方法看附件
Block循环引用的问题
快速定位Block循环引用所处位置
然而凡事都不会尽善尽美,智能指针的循环引用缺陷还是会引发令人谈虎色变的内存泄露。本文的内容是讲述,如何解决循环引用带来的内存问题。 背景:智能指针采用Boost库,语言C++,开发工具VS2005,示例程序为Win...
利用Excel的循环引用自动完成迭代计算 包括计算宏等内容
头插法之循环引用(形成环形链表)问题及解决
循环引用导致某一方的引用字段不参与序列化
循环引用的判断我们可以通过map来进行暂存,当值是对象的情况下,我们将对象存在map中,循环判断是否存在,如果存在就是存在环了,同时进行递归调用。let has
虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧
下面一段代码给大家介绍iOS MRC 下 block 循环引用问题 //注意此__block会复制一份指针出来 一次原始的指针如果置为nil的话,此处复制出来的指针还是野指针 __block __typeof(self)weakSelf = self; //__weak _...
我们都知道NSTimer采用target-action的方式,通常target又是类本身,我们为了方便又把NSTimer声明为属性变量,这样就难免会造成循环引用(需要反复执行计时任务时,如果是单次的任务就不会造成循环引用)。...