【JavaScript】面试手撕浅拷贝

引入

浅拷贝和深拷贝应该是面试时非常常见的问题了,为了能将这两者说清楚,于是打算用两篇文章分别解释下深浅拷贝。

PS: 我第一次听到拷贝这个词,有种莫名的熟悉感,感觉跟某个英文很相似,后来发现确实Copy的音译,感觉这翻译还是蛮有意思的。🐶

什么是浅拷贝

行文至此,肯定会有朋友问,什么事浅拷贝呢?顾名思义,就是浅浅的copy一下。🐶

JavaScript中,对于浅拷贝分为两种情况。

  • 对于浅拷贝,如果待拷贝的数据是基础类型的属性(如NumberStringBoolean等基本类型),那么只需要将这个值直接复制过来即可
  • 对于浅拷贝,如果待拷贝的数据是引用类型的属性(如对象,数组),那么复制的则是对象的引用以及第一层的基础属性值

基础类型与引用类型的区别

谈到这,顺带谈一下基础类型引用类型的区别。

基础类型

  • 直接存储在栈内存中。
  • 存储的是实际的数据值。
  • 内存空间固定且较小。

引用类型

  • 对象(如数组,函数,对象等)的属性值存在堆内存中。
  • 栈内存中存储的是指向堆内存中对象的引用或指针,而非对象本身的内容。
  • 内存空间大小不固定,取决于对象结构的复杂性。

手动实现浅拷贝

因为值的拷贝可以直接赋值即可。我们这里实现下对象的浅拷贝。

对象的浅拷贝:复制对象的引用以及第一层属性值。

思路: 我们先构造一个新对象,然后将它的属性值等于原对象的属性值。这里新对象和原对象的属性依然会共享引用,但对于第一层的基础属性却不会共享了。所以我们实现的浅拷贝 是拷贝一层。

js 复制代码
function shallowClone(obj) {
  const newObj = {};
  for (let prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      newObj[prop] = obj[prop];
    }
  }
  return newObj;
}

const test = { a: 1, b: 2 };
const newTest = shallowClone(test);
newTest.a = 2;
console.log('test: ',test,' newTest: ', newTest);
/**
 * 输入如下,第一层基础属性的值不会共享了
 * test:  { a: 1, b: 2 }  newTest:  { a: 2, b: 2 }
 */

Js自带浅拷贝的方法

对于Js的浅拷贝,可以分为对象浅拷贝数组浅拷贝

对象浅拷贝

对于对象的浅拷贝有object.assgin拓展运算符实现,这里的浅拷贝都是拷贝一层。

Object.assign

Object.assign()ES6 中引入的一个方法,用于将一个或多个源对象的所有可枚举属性分配到目标对象上。

js 复制代码
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);

拓展运算符

注意:这种方式同样会创建一个新的对象,但对嵌套对象或数组只会进行浅拷贝。

js 复制代码
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };

数组浅拷贝

slice

slice()方法是用来从数组中提取一部分元素生成新数组的方法,它确实实现了数组的浅拷贝。

js 复制代码
let originalArray = [1, 2, { a: 3 }, [4, 5]];
let copiedArray = originalArray.slice();

// 浅拷贝后,原始数组和拷贝数组中基本类型元素是独立的
copiedArray[0] = 100; // 修改基本类型元素,不影响原数组
console.log(originalArray); // 输出:[1, 2, { a: 3 }, [4, 5]]
console.log(copiedArray); // 输出:[100, 2, { a: 3 }, [4, 5]]

// 但是对于引用类型元素,修改其属性或内容会同时影响原数组和拷贝数组
copiedArray[2].a = 456;
copiedArray[3][0] = 7;

console.log(originalArray); // 输出:[1, 2, { a: 456 }, [7, 5]]
console.log(copiedArray); // 输出:[100, 2, { a: 456 }, [7, 5]]
相关推荐
mCell2 小时前
AI 时代 SVG 画图的潜力
前端·agent·svg
我命由我123458 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
Hopebearer_9 小时前
页面突然只剩 DOM?一次静态资源版本错配排查
前端·部署
抱抱宝9 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
东风破_9 小时前
ESLint 是什么?为什么你的项目需要它?
前端·后端·代码规范
用户938515635079 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
圣殿骑士-Khtangc11 小时前
Go字符串高效拼接性能对比与底层原理分析
服务器·前端·golang
ShineWinsu11 小时前
对于C++:C++11中lambda、function、bind的解析
c++·面试·笔试·开发·lambda·bind·function
码匠许师傅11 小时前
【C++ 面试真题】聊聊 C++ 的拷贝构造与拷贝赋值
java·c++·面试
BigTopOne11 小时前
【ijkplayer】 硬解码流程
前端