当前位置: 首页 > 网络应用技术

正面 - 末端采访手写代码系列(1):深克隆方法

时间:2023-03-06 21:15:22 网络应用技术

  大家好,我迟到了。

  手写代码是前端访谈中必不可少的链接,基本上列举了常见的手写代码问题。互联网上还有很多文章,他们将谈论手写代码,但其中大多数人不够全面且足够深。一些低质量的文章甚至会误导初学者。因此,它计划在[前端手写代码]中发布一系列文章,并在全面而深刻的解释和深度解释和深入的解释中解释常见的前端访谈手写代码问题使用手写代码问题扩展面试官想要检查的基本能力。为了确保全面深度的深度,本系列文章将涉及其他出色的文章,并将参考文章附加到参考材料上。

  从今天的《深度克隆》开始,深圳克隆是前端访谈中很高的频率手写代码问题。我相信,具有一定前端的面试经验的前端学生已经手写了,但是在继续查看以下内容之前,请询问这三个三个。

  要了解深圳克隆和浅克隆之间的差异,您需要了解JavaScript中基本类型和参考类型之间的差异。

  JavaScript中有两种不同的数据类型:基本类型和参考类型。

  基本类型包括数字,布尔值,字符串,符号,空和未定义;

  参考类型包括对象,数组,功能等。

  基本类型的传输方法按值传递,并通过参考传递参考类型的传输方法。

  按值传递意味着每个分配都分配给一个变量,并且值的副本将分配给该变量;

  在下面的示例中,解释过程可以按值传递。

  将A分配给B,A的值的副本将分配给B.重新分配B时,对A.So a的影响没有影响!==B。

  根据引用(通过参考文献传递),它只会传递对对象的引用,而不是对象的副本。引用相同的两个对象并修改任何对象将相互影响。

  如下所示,X是数组数组类型。数组类型是参考类型。数组类型本质上是对象类型子类型。变量X分配到变量y,仅将x的引用传递给y。在这次时,x和y在同一数组中具有共同的引用。

  如下示例所示,修改任何变量x和y都会影响另一个,因为x和y具有相同数组的引用:

  深圳克隆和沙龙之间的区别在于,当复制浅的克隆参考类型对象时,将传递相同的引用到新的克隆对象。当复制深克隆参考类型对象时,参考类型值的副本将传递给参考类型的值的副本到副本tonew克隆对象。因为浅克隆不需要复制该值对象类型,它比深克隆性能更好。

  两张图片来解释Qian克隆和深克隆之间的区别:

  Qian Clone:

  深克隆:

  了解深克隆和浅克隆的概念,现在我们来正式的手写代码来实现深层克隆。

  实现深克隆的最简单方法是使用json.parse(json.stringify(target)),但是该方法具有明显的缺陷,例如:::::

  因此,我们需要手动实施一种深层克隆方法。

  首先,让我们意识到一个浅的克隆,通过遍历实现目标对象的克隆。

  如果我们想实现一个深层的克隆,我们需要基于上述两个新的逻辑:

  上面的实现基本上可以满足对象类型的类型时的需求。但是如果它是数组类型,上面的实现将把数组变成对象。因此,我们将下一步考虑兼容的组。

  当我们考虑数组时,我们将涉及一个新的知识点,即如何判断数组的类型。

  JavaScript的类型判断具有以下方法:

  在这里,一些初学者可以使用TypeOF来判断类型,但是TypeOf不能判断数组类型。

  TypeOF的返回类型如下:

  TypeOF数组的返回值也是对象。

  接下来,我们考虑代码实现中数组类型的情况。

  当对象通过上述实现引用和实施时会发生什么?

  使用上述代码,我们将获得以下结果。

  由于OBJ中有一个周期参考,因此Clonedeep的调用将无限循环,最终导致内存溢出。

  为了解决上述问题,我们需要一个存储空间来存储当前对象和复制对象之间的关系。如果当前对象已复制,它将直接返回到存储的复制对象。如果未复制,请在存储空间中复制并复制复制对象存储。该存储空间需要键值的形式,因此我们选择要存储的地图。

  使用地图的实现方法如下:

  复制上述周期参考OBJ的对象,并获得以下结果:

  带有周期参考的对象可以是深处并正常克隆的。

  熟悉ES6的学生一定会想到Map的双胞胎姐妹弱图。在这里,我们可以继续用弱图优化我们的实施。

  弱图是弱参考的关键值。钥匙值必须是一个对象,并且值可以是任何类型。映射的区别在于地图是一个强引用,而fealmap是弱参考。

  与地图对象不同,弱图密钥是不可或缺的。没有列出其密钥的方法

  什么是弱参考?弱参考意味着如果没有其他参考,可以通过垃圾回收机制来回收弱参考的对象。如果仅存在一个对象,则该对象在实施垃圾回收机制期间将被回收。

  当我们是深克隆的大型对象时,使用地图将导致大量的性能损失,并且我们必须手动清除地图的键值以释放内存。WeakMap不会遇到此问题。

  在上述实施中,我们获得的方法是... in ...,但是... in存在问题。除了符号外,它将在原型链上获得所有枚举属性。对于深克隆,只需要克隆对象的属性,并且不需要克隆的原始链上的非self -self -attributes。对象本身的属性?

  有几种获取对象自身属性的方法:

  可以看出,如果我们的目标是获得对象本身的所有属性,则object.getownpropertynames()是一种合适的方法。

  基于上述分析,我们的实现继续优化。

  在上面的实现中,我们仅考虑普通对象和数组。

  我们如何获得真实的引号类型?通过object.prototype.tring方法,我们可以观察到不同对象的各种示例的tostring将遵循相同的格式输出。

  因此,可以通过以下方法:

  其中,符号类型需要特别注意:

  符号是一种基本数据类型。符号()函数返回具有静态属性和静态方法的符号类型的值。ITS静态属性将暴露几个构建的成员;它的静态方法将公开与构建的对象类相似的全局符号注册,但由于不支持语法,因此并不完整作为构造函数:“ new符号()”。

  您可以通过以下方式创建符号类型的数据:

  符号类型不能由新符号()方法创建,因为符号不是构造函数。

  如果您真的想创建一个符号对象,则可以使用以下方式:

  接下来,我们将支持映射,设置,regexp,number,字符串,布尔值,日期,错误,null类型和符号对象类型。符号对象类型是指通过路的符号类型。

  基于上述优化,我们最终意识到了与各种情况兼容的深克隆方法,并测试了验证函数的正确性:

  在上一篇文章中,通过连续优化深克隆方法,我们扩展了以下知识点:

  通过上述,我们继续优化深克隆的方法,并逐渐支持所有基本类型(number/boolean/string/undefined/bigint/function/符号),object/array/map/map/symbor/error,支持/regex/数字/字符串/布尔/日期/null),并考虑了与原型链,周期参考等的兼容性。

  请访问其他“外国面试手写代码系列”,欢迎更多其他内容访问当晚的主页。

  原始:https://juejin.cn/post/7103797984063651853