← 返回目录

第 5 卷

第 5 / 8 卷日期:

九、手写浅拷贝函数的代码实现

核心原理

  1. 浅拷贝:只复制对象的“表层属性”,若属性值是引用类型(对象/数组等),则复制的是引用地

址,原对象和拷贝对象会共享该引用类型数据

  1. 支持类型:对象(普通对象、数组、类数组)、基本类型(直接返回原值)
  2. 实现思路:遍历原对象的可枚举属性,将属性值直接赋值到新对象中

实现代码

Code block

1function shallowClone(target) {

2// 1.处理基本类型和null(基本类型直接返回原值,null无需拷贝)
3if (target === null || typeof target !== 'object') {
4return target;
5}

6 7// 2. 处理数组:创建新数组,遍历赋值

8if (Array.isArray(target)) { 9return [...target]; // 或 Array.from(target)、target.slice()

10} 11

12// 3.处理类数组(如arguments、DOM集合):转为数组后返回
13if (target.length !== undefined && typeof target.length === 'number') {
14return Array.from(target);
15}

16

17// 4.处理普通对象:创建新对象,遍历可枚举属性赋值
18const cloneObj = {};
19for (let key in target) {
20//只复制自身的可枚举属性(不复制原型链上的属性)
21if (target.hasOwnProperty(key)) {
22cloneObj[key] = target[key];
23}
24}
25return cloneObj;
26}

27 28// 测试示例

29// 1. 基本类型测试 30console.log(shallowClone(123)); // 123

31console.log(shallowClone('abc')); // 'abc'

37arr2[0] = 100; //修改基本类型属性,不影响原数组
38arr2[2].a = 300; //修改引用类型属性,影响原数组
39console.log(arr1); // [1, 2, { a: 300 }]
40console.log(arr2); // [100, 2, { a: 300 }]

41 42// 3. 普通对象测试

43const obj1 = { name: '浅拷贝', user: { age: 20 } };
44const obj2 = shallowClone(obj1);
45obj2.name = '修改后'; //基本类型不共享
46obj2.user.age = 21; //引用类型共享
47console.log(obj1); // { name: '浅拷贝', user: { age: 21 } }
48console.log(obj2); // { name: '修改后', user: { age: 21 } }

49 50// 4. 类数组测试

51function testArgs() {

52const argsClone = shallowClone(arguments);
53console.log(argsClone); // [1, 2, 3](数组类型)
54}
55testArgs(1, 2, 3);

56

十、手写深拷贝函数的代码实现

核心原理

  1. 深拷贝:复制对象的所有层级属性,包括引用类型属性,原对象和拷贝对象完全独立,互不影响
  2. 解决问题:浅拷贝的引用共享问题、循环引用问题(如obj.a = obj)、特殊类型处理(Date、

RegExp、Function等)

  1. 实现思路:递归遍历原对象,遇到引用类型时,创建新的对应类型对象,继续递归拷贝其属性;遇

到基本类型直接赋值

实现代码

Code block

1function deepClone(target, map = new WeakMap()) {

2// 1.处理基本类型和null(直接返回原值)
3if (target === null || typeof target !== 'object') {
4return target;

11 12let cloneObj;

13 14// 3. 处理特殊引用类型

15// 3.1 处理Date 16if (target instanceof Date) {

17cloneObj = new Date(target);

18map.set(target, cloneObj);

19return cloneObj;

20} 21

22// 3.2 处理RegExp 23if (target instanceof RegExp) {

24cloneObj = new RegExp(target.source, target.flags);
25map.set(target, cloneObj);
26return cloneObj;
27}

28 29// 3.3 处理数组

30if (target instanceof Array) { 31cloneObj = [];

32map.set(target, cloneObj); //先缓存,避免循环引用
33//递归拷贝数组元素
34target.forEach((item, index) => {
35cloneObj[index] = deepClone(item, map);
36});
37return cloneObj;
38}

39 40// 3.4 处理普通对象(包括自定义类实例)

41if (target instanceof Object) { 42cloneObj = {};

43map.set(target, cloneObj); //缓存,避免循环引用
44//遍历对象自身的可枚举属性(包括Symbol属性)
45const keys = [...Object.keys(target),

...Object.getOwnPropertySymbols(target)];

46keys.forEach(key => { 47// 递归拷贝属性值

48cloneObj[key] = deepClone(target[key], map);

49});

50return cloneObj;

全站分卷索引 · 8 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷