【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归但循环引用会导致指针无法断开,请看如下代码:由于a和b两个对象互相引用指针,形成了闭环,就会导致无法触发GC,所占资源也就无法释放。

欢迎大家来到IT世界,在知识的湖畔探索吧!

写在前面:本文为DataHunter前端技术培训系列的第一篇文章,后续将有更多精彩内容放出,赶紧关注我们的公众号来get实时更新吧!

循环引用陷阱

JavaScript的GC机制是自动进行。当一个对象断开所有的指针引用以后,GC就会回收这部分资源。但循环引用会导致指针无法断开,请看如下代码:

【前端底层技术课堂】JavaScript对象的序列化和分支递归

由于a和b两个对象互相引用指针,形成了闭环,就会导致无法触发GC,所占资源也就无法释放。

在JSON.stringify对JavaScript数据结构进行序列化的时候,也会遇到循环引用的陷阱。例如:

【前端底层技术课堂】JavaScript对象的序列化和分支递归

JavaScript的数据类型和JSON序列化策略

通过JavaScript的typeof操作符,我们可以得到的数据类型有

string/number/ function/boolean/symbol/object/undefined。

其中object包括Object/Array/RegExp/Date/null等,function包括class类。所有这些类型,从JSON序列化的角度,我们可以分为三类:

【前端底层技术课堂】JavaScript对象的序列化和分支递归

由于JSON标准只具备string/number/boolean/null等有限的几种值类型,所以JS对象在序列化后会有变化。下面是几种特殊类型在转换时需要注意的问题:

  • function无法被序列化。

  • Symbol对象无法被序列化。

  • Date对象无法被序列化。

  • ES6的class的typeof是function,无法序列化。

  • number的NaN会被转成null。

  • RegExp默认会被转成空对象。

  • TypedArray并不继承自Array,所以会被序列化成对象而不是数组。

  • undefined由于会被JSON忽略,所以反序列化后对象会有键的变化。看例子:

【前端底层技术课堂】JavaScript对象的序列化和分支递归

可以看到,in操作符在obj和copy两个对象中会出现不同的返回结果。所以在对反序列化的数据进行操作时,in操作符要小心使用。

通过JSON的序列化策略我们可以看出,循环引用可能会发生在mixed类型上,所以我们可以在序列化过程的最外层,建立一个mixed指针的数组。当数组已经具备此指针,就可以断定该指针数据已经被序列化,从而中断进一步序列化过程。

首先我们写一个mixed类型判断函数:

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

通过JSON.stringify的第二个回调处理理函数参数,我们植入这个类型判断,并启用循环引用陷阱规避。

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

JavaScript对象的分支递归和深拷贝

我们知道,Object.assign会实现一次Object或者Array的浅拷贝。但这种浅拷贝有时并不能满足我们的需求。有时我们还会需要对对象的分支做值更改检测,或者分支合并。这时候都需要对对象的所有分支做一次递归。

JSON.stringify其实就是做了了一次分支递归。对象分支递归的策略和序列化策略基本一致,我们拿对象的深拷贝来举例说明。

我们首先针对上述三种数据类型,做一个类型判断函数。

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

此外,由于Object和Array都是mixed类型,但不是同一个构造函数,所以我们需要对Object和Array再做一次类型细分,以便构造新的复制对象。

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

创建一个分支递函数,并规避循环引用陷阱。

【前端底层技术课堂】JavaScript对象的序列化和分支递归

【前端底层技术课堂】JavaScript对象的序列化和分支递归

可以看到循环引用的部分都变成undefined了。

在ES6下,可以通过Symbol对象定义一个循环引用的标记并返回,在运行时对此类值做自定义的处理,防止对象log出来太难看。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/35456.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信