返回

Recursion Is Far From The Only Detail Of Deep Copy (Part 2)

前端

深拷贝细节远不止递归(下篇)

处理循环引用

循环引用是指两个或多个对象相互引用,形成环形结构。在 JavaScript 中,对象是引用类型,因此两个对象可以相互引用,而无需直接存储对方的副本。当尝试对包含循环引用的对象进行深拷贝时,可能会陷入无限循环,从而导致错误。

lodash 通过使用一个哈希表来跟踪已经复制过的对象来处理循环引用。当遇到一个对象时,它首先检查哈希表中是否已经存在该对象。如果存在,则直接返回该对象的副本,从而避免无限循环。如果不存在,则将该对象添加到哈希表中,然后对其进行深拷贝。深拷贝完成后,将该对象从哈希表中删除。

递归

递归是一种函数调用自身的方法。在 JavaScript 中,函数可以调用自身,从而形成递归结构。当尝试对包含递归引用的对象进行深拷贝时,可能会陷入无限循环,从而导致错误。

lodash 通过使用一个栈来跟踪正在复制的对象来处理递归引用。当遇到一个对象时,它首先检查栈中是否已经存在该对象。如果存在,则直接返回该对象的副本,从而避免无限循环。如果不存在,则将该对象添加到栈中,然后对其进行深拷贝。深拷贝完成后,将该对象从栈中删除。

函数

函数是 JavaScript 中的一等公民,这意味着它们可以像其他值一样被赋值、传递和返回。当尝试对包含函数的对象进行深拷贝时,需要特殊处理,因为函数不能直接复制。

lodash 通过创建一个新函数来处理函数。新函数与原始函数具有相同的代码,但具有不同的作用域。这样可以确保新函数不会访问原始函数的作用域,从而避免引用错误。

过滤原型属性

原型属性是 JavaScript 中对象的一种特殊属性。原型属性是通过原型链继承的,而不是直接存储在对象中。当尝试对包含原型属性的对象进行深拷贝时,需要特殊处理,因为原型属性不是对象本身的一部分。

lodash 通过使用一个过滤函数来过滤原型属性。过滤函数将对象的所有属性遍历一遍,并返回一个包含非原型属性的数组。然后,对这个数组进行深拷贝,从而得到一个不包含原型属性的对象副本。

对象循环引用

对象循环引用是指一个对象直接或间接地引用自身。当尝试对包含对象循环引用的对象进行深拷贝时,可能会陷入无限循环,从而导致错误。

lodash 通过使用一个哈希表来跟踪已经复制过的对象来处理对象循环引用。当遇到一个对象时,它首先检查哈希表中是否已经存在该对象。如果存在,则直接返回该对象的副本,从而避免无限循环。如果不存在,则将该对象添加到哈希表中,然后对其进行深拷贝。深拷贝完成后,将该对象从哈希表中删除。

结论

深拷贝是一个复杂的过程,涉及到许多细节。lodash 通过使用哈希表、栈、过滤函数等数据结构和算法来处理各种情况,从而实现了对对象的深拷贝。通过理解这些细节,我们可以更好地理解 lodash 的工作原理,并将其应用到我们的项目中。