ES6时代,你真的会克隆对象吗(二)

原文:ES6时代,你真的会克隆对象吗(二)

上一篇,我们从Symbol和是否可枚举以及属性描述符的角度分析了ES6下怎么浅拷贝一个对象,发表在掘金segmentfault上,从评论看,部分人觉着看不懂,今天,我们用更简单的方式来聊聊深拷贝的问题

写在前面

深拷贝的话题好像从来没有停止过讨论,JavaScript并没有一个可以实现深拷贝的方法,我们常见的实现方式是递归和JSON.parse(JSON.stringify())(听说底层还是用了递归),然而一般库函数也只能处理常见的需求(不常见的需求真的存在吗?真的需要用深拷贝吗?真的不承认是你代码的问题吗?)。今天,我就仔细、认真,细致(也不是很细致),负责(也不敢太保证)的态度来研究一下怎么实现一个深拷贝吧,虽然一度放弃,事实也的确是放弃了,但不把这么多天的付出写出来怎么对得起那个在这个寒冷的冬天忍住瑟瑟发抖的在键盘上敲击的我...

常见深拷贝

JSON系列化

JSON.parse(JSON.stringify())的确是一种很简单易用的方式呢,可惜的是,JSON是一个很有原则的男人,他可不会对你言听计从。在遇到不安全的JSON值会自动将其忽略,在数组中则会返回null(以保证单元位置不变)。

不安全的 JSON 值: undefined 、 function 、 symbol (ES6+)和包含循环引用(对象之间相互引用,形成一个无限循环)的 对象 都不符合 JSON 结构标准,支持 JSON 的语言无法处理它们

递归

上一篇讲浅拷贝的时候,我们在开始引入了一个浅拷贝的例子,现在我们把它改成一件简单的深拷贝。

function deepCopy (obj) {
  if (typeof obj !== 'object') {
    return
  }
  var newObj = obj instanceof Array ? [] : {}
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]
    }
  }
  return newObj
}

好像也还不错,简单易懂还能用,一般的场景的确是一种不错的方法呢,但是,今天我们来看看不一般的场景。

我们先来挑挑毛病:

  • function类型没有处理(大概,或许,应该是真的没必要吧,下面我也并不打算讨论这货,有兴趣的去看看callapplybind
  • 循环引用
  • 类型判断用typeofinstanceof靠谱吗?(特别注意typeof null的坑)
  • 数组?[]:{},这么简单?不存在的

循环引用

上面多处说到了循环引用的问题,我们先来看看什么是循环引用:

var a = {}
a.b = a

是的,就是这么一个反人类的存在,但是却是我们不能忽略的一个大问题。我们是应该返回空呢、undefined呢,还是它的引用,还是什么呢?好像没有标准答案呢,嗯,那就Follow Your Heart吧!

类型判断

思考一下:

typeof null  // "object"
null instanceof Object  // false

进行类型判断是无可避免的,然而我们似乎并没有什么完美的方式得到我们需要的类型,我们先来看看几种常用的方式:

  • typeof: 返回一个表达式的数据类型的字符串,返回结果为js基本的数据类型,包括number,boolean,string,object,undefined,function,symbol
  • instanceof: 判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例;返回boolean类型。内建类型只有通过构造器才能用instanceof
  • constructor: 是每一个实例对象都拥有的属性,而这个属性也相当于是一个指针,它指向于创建当前对象的对象
  • Object.prototype.toString.call(obj).slice(8,-1): 返回的是类名

typeof的问题就很明显了:

typeof null  // "object"
typeof function () {}  // "function"
typeof []  // "object"

instanceof考虑一下多全局对象(多个frame或多个window之间的交互),在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回false,因为 Array.prototype !== window.frames[0].Array.prototype

constructor属性得到的仅仅是构造函数,而且是可以被手动更改的,constructor.name只是返回的构造函数的名字,它并不返回类名。

Object.prototype.toString.call算是比较公认靠谱的方法了吧,然而,它同样有可能被人为仿造,鸭子类型嘛,但它还是比较安全的方式。

鸭子类型: "如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子"。动态类型的语言倾向于你让它做什么它就是什么

类型分析

讨论铺垫的内容应该够细了吧,接下来我们看看js的复杂数据类型到底有多复杂。

我们常见的有:

基本包装类型(Boolean、String、Number)、function、Array、Date

你常见,但你不一定想的起的:

RegExp,Arguments,Error、NodeList

你不一定常见,你也不一定知道的:

Blob、File、FileList、ImageData

ES6:

Map、Set、WeakMap、WeakSet、ArrayBuffer对象、TypedArray视图和DataView视图、Float32Array、Float64Array、Int8Array...

或许列举的少了不少,但是已经够让人担忧深克隆的复杂程度了,一一实现他们不是一件简单的事情,甚至是一件完全没有必要的事情(当然可以让你了解更多),推荐几个很优秀的方案供参考:

  • lodash克隆,lodash花了大量的代码来实现 ES6 引入的大量新的标准对象。更厉害的是,lodash 针对存在环的对象的处理也是非常出色的
  • jQuery克隆无法正确深复制 JSON 对象以外的对象
  • 结构化克隆算法

写在最后

克隆的部分就写的差不多了,本来想写点Map、Set的内容的,无赖,并没有找到合适的地方,MDN阮一峰的ECMAScript 6 入门都介绍的挺好的。

好吧,就这样吧,前端界的小学生,不足之处,还请指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,548评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,069评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,985评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,305评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,324评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,030评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,639评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,552评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,081评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,194评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,327评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,004评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,688评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,188评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,307评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,667评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,337评论 2 358

推荐阅读更多精彩内容