面试官:(...)扩展运算符是深拷贝吗?

大家好,我是勇宝,一名正在学习前端的打工仔,欢迎大家关注我,一起探讨更多前端小知识。今天我们来好好唠一唠深浅拷贝

一、情景再现

金三银四,最近找工作的小伙伴是扑面而来,这其中少不了我的好朋友张某某同学,我们'相依为命',我经常开导他,这不最近的一次面试中他就遇到这样一个考题:

面试官:(...)是深拷贝吗?

二、JavaScript数据类型

在聊深浅拷贝之前,我们先来说一说JS中的数据类型:

我们都知道JavaScript中有两种数据类型(基本类型引用类型),那么我就先考考大家:数据类型都有什么?

  • 基本数据类型 :String(字符串)、Number(数值)、Boolean(布尔值)、Null、Undefined、Symbol;
    • 基本数据类型是直接存储在栈中。
  • 引用数据类型 :Array、Object;
    • 引用类型存储的是该对象在栈中的引用,真正的数据是存储在内存(堆)中的。

举例一

js 复制代码
let name = 'iyongbao';
let name2 = name;

name2 = 'zhangsan';

console.log(name); // iyongbao
console.log(name2); // zhangsan

举例二

js 复制代码
let obj = { name: 'iyongbao' };
let obj2 = obj;

obj2.name = 'zhangsan';

console.log(obj); // {name: "zhangsan"}
console.log(obj2); // {name: "zhangsan"}

上线的案例都是'拷贝',从中我们可以看到,引用类型的赋值会影响到原数据,这其实就是浅拷贝

二、探究深浅拷贝

对于深浅拷贝,勇宝给出自己的理解:

浅拷贝:对于浅拷贝也就是基本数据类型,拷贝后的值无论怎么变化都不会影响到原数据;而对于引用类型来说,有的人认为浅拷贝是会拷贝对象的第一层值,也就是说对象通过浅拷贝当我们修改新复制对象的一层属性时,原数据不会发生改变。

深拷贝:无限层级拷贝。在深拷贝中,修改基本数据类型和引用数据类型都不会影响原有的数据类型。

js 复制代码
// 浅拷贝
let obj = { a: 1, b: { c: 2 } };

let obj2 = { ...obj };

obj2.a = 3;
obj2.b.c = 4;

console.log(obj); // {a:1, b: { c: 4 }}
console.log(obj2); // {a: 3, b: { c: 4 }}

结论 :通过上边的案例,我们可以看出...(拓展运算符)是一个浅拷贝

js 复制代码
// 深拷贝
let obj = { a: 1, b: { c: 2 } };

let obj2 = JSON.parse(JSON.stringify(obj));

obj2.a = 3;
obj2.b.c = 4;

console.log(obj); // {a:1, b: { c: 2 }}
console.log(obj2); // {a: 3, b: { c: 4 }}

关于JSON.stringify大家可以看一看我的另一篇文章:你不知道的JSON.stringify神操

三、浅拷贝方法

3.1 直接赋值

js 复制代码
let obj = {
    name: 'iyongbao',
    age: 26
}

let obj2 = obj;
obj2.name = "zhangsan";

console.log(obj); // {name: "zhangsan", age: 26}
console.log(obj2); // {name: "zhangsan", age: 26}

3.2 Object.assign

js 复制代码
let obj = {
    name: 'iyongbao',
    score: {
        vue: 98
    }
}

let obj2 = Object.assign({}, obj);

obj2.name = "zhangsan";
obj2.score.vue = 60;

console.log(obj); // {name: "iyongbao", score: { vue: 60 }}
console.log(obj2); // {name: "zhangsan", score: { vue: 60 }}

注意 :使用Object.assign第一层是深拷贝。

3.3 扩展运算符

js 复制代码
let obj = {
    name: 'iyongbao',
    score: {
        vue: 98
    }
}

let obj2 = { ...obj };

obj2.name = "zhangsan";
obj2.score.vue = 60;

console.log(obj); // {name: "iyongbao", score: { vue: 60 }}
console.log(obj2); // {name: "zhangsan", score: { vue: 60 }}

注意扩展运算符Object.assign的效果一样。

3.4 slice和concat

slice是截取数组,concat是拼接数组。

js 复制代码
let obj = ['iyongbao', score: { vue: 98 }]

let obj2 = obj.slice();
let obj3 = obj.concat();

obj[0] = "zhangsan";
obj[1].vue = 60;

console.log(obj); // {name: "zhangsan", score: { vue: 60 }}
console.log(obj2); // {name: "iyongbao", score: { vue: 60 }}
console.log(obj3); // {name: "iyongbao", score: { vue: 60 }}

四、深拷贝方法

4.1 JSON.parse(JSON.stringify(待拷贝对象))

这里使用的还挺多的。

js 复制代码
let obj = {
    name: 'iyongbao',
    age: 26
}

let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = "zhangsan";

console.log(obj); // {name: "iyongbao", age: 26}
console.log(obj2); // {name: "zhangsan", age: 26}

4.2 使用第三方库 Lodash

js 复制代码
const _ = require('lodash');

let obj = {
    name: 'iyongbao',
    age: 26
}

let obj2 = _.cloneDeep(obj);
obj2.name = "zhangsan";

console.log(obj); // {name: "iyongbao", age: 26}
console.log(obj2); // {name: "zhangsan", age: 26}

4.3、手写一个深拷贝

JSON.stringify还是存在一些不足的,比如对`(函数、undefined、正则、Symbol)不友好,下面我们就自己来动手写一个简单的深拷贝方法。

js 复制代码
function deepClone (obj) {
    if (typeof obj !== 'object' || obj == null) {
        return obj;
    }
    
    let deepCloneObj = Array.isArray(obj) ? [] : {}
    
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            deepCloneObj[key] = deepClone(obj[key]);
        }
    }
}

五、总结

深浅拷贝JavaScript开发中有着不同的应用场景和实现方式。了解它们的区别对于正确处理对象和数组的赋值是至关重要的。希望通过今天的分享,能够帮助小伙伴们更好的去加深与理解。

相关推荐
明辉光焱9 分钟前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛30 分钟前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端
开心工作室_kaic1 小时前
ssm111基于MVC的舞蹈网站的设计与实现+vue(论文+源码)_kaic
前端·vue.js·mvc
云空1 小时前
《InsCode AI IDE:编程新时代的引领者》
java·javascript·c++·ide·人工智能·python·php
晨曦_子画1 小时前
用于在 .NET 中构建 Web API 的 FastEndpoints 入门
前端·.net
慧都小妮子1 小时前
Spire.PDF for .NET【页面设置】演示:在 PDF 文件中添加图像作为页面背景
前端·pdf·.net·spire.pdf
咔咔库奇1 小时前
ES6基础
前端·javascript·es6
Jiaberrr1 小时前
开启鸿蒙开发之旅:交互——点击事件
前端·华为·交互·harmonyos·鸿蒙
徐小夕2 小时前
Flowmix/Docx 多模态文档编辑器:V1.3.5版本,全面升级
前端·javascript·架构