likes
comments
collection
share

当面试官让你谈谈深浅拷贝,你怎么说?

作者站长头像
站长
· 阅读数 2

前言

是什么?

  • 浅拷贝: 只拷贝一层对象,复制这一层对象中原始类型的属性值,如果有引用类型的话,就复制它的指针(引用地址)
  • 深拷贝: 层层拷贝,所有类型的属性值都会被复制,原对象的修改不会影响拷贝后的对象
  • 深浅拷贝通常只针对引用类型: 原始类型拷贝后修改原属性值不会对拷贝后的值产生影响,所以讨论原始类型的深浅拷贝没有意义,或者说原始类型都是深拷贝

如何实现深浅拷贝的效果?

  • 浅拷贝Object.assign concat slice [...arr] 这里很多人会有疑惑,concatslice不是数组上面的方法吗?但是大家可能忽略了一个问题,数组也是引用类型,深浅拷贝针对的是所有的引用类型,所以数组也算在内。
let obj = {
    a: 1,
    b: 2
}
let newObj = Object.assign({}, obj)

let arr = [1,2,3]
let newArr = [].concat(arr)
arr.push(4)
console.log(newArr);    // [1,2,3],不影响新数组

// 但是如果这样写就会影响
let arr2 = [1,2,3,{n: 4}]
let newArr2 = [].concat(arr2)
arr2[3].n = 5
console.log(newArr2);   // [1,2,3,{n: 5}]

let newArr = arr.slice(0,arr.length)
let newArr = [...arr]

其实还有一个方法,也能实现浅拷贝效果,就是Object.create(obj),但是它一般不放在浅拷贝的范畴里。

let obj = {
    a: 1,
    b: 2
}
let newObj2 = Object.create(obj)
console.log(newObj2);   // {}
console.log(newObj2.a);   // 1

因为Object.create(obj)创建了一个新的空对象newObj2,让newObj2隐式继承了obj的属性,即执行了一个这样的操作newObj2.__proto__ = obj,深浅拷贝一般指的是拷贝对象上的显式具有的属性,所以Object.create(obj)就没被算在内,但是你把这个告诉面试官,同样会让他对你眼前一亮。

  • 深拷贝: 实现深拷贝就这一个方法JSON.parse(JSON.stringify(obj)),但是它有一个缺陷就是不能拷贝undefinedSymbolfunction,它的原理很简单,就是把对象先转为字符串,然后再转为对象,这样拷贝前后的两个对象就是两个单独的个体,有两个不同的引用地址,就不会相互影响。

如何实现深浅拷贝?

注意审题哦,这里说的是如何实现深浅拷贝?,而不是如何实现深浅拷贝的效果?,它的意思是让你手动实现深浅拷贝,要你手撕代码。

  • 浅拷贝: 这里就有一点要注意一下,拷贝是拷贝对象显式具有的属性,所以在拷贝前要先判断该属性是不是对象显式具有的
function shallowCopy(obj) {
    let newObj = {}
    for (let key in obj) {
        // 判断该属性是否是原对象显式具有的属性
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key]
        }        
    }
    return newObj
}
  • 深拷贝: 实现深拷贝常见的就是递归,相信很多人都会选择用这个方法。
function deepCopy(obj) {
    let newObj = {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] !== 'object' || obj[key] === null) {    // 原始类型
                newObj[key] = obj[key]
            } else {
                newObj[key] = deepCopy(obj[key])
            }
        }
    }

    return newObj
}

这里再给大家介绍一个进阶版的方法structuredClone(obj),这是es6新增的专门用来实现深拷贝的方法,但它一样有个缺陷,就是不能拷贝Symbolfunction 但是相较于JSON.parse(JSON.stringify(obj))来说,它能够拷贝undefined

let obj = {
    a: 1,
    b: {
        n: 2
    },
    c: undefined
}
const obj2 = structuredClone(obj)
console.log(obj2);   // { a: 1, b: { n: 2 }, c: undefined }

结语

js中的深浅拷贝是面试里常考的题目之一,虽然也比较简单,但是给大家介绍了一些进阶版的回答是不是更能提高面试官对你的好感度呢?