扫码关注微信公众号

回复“面试手册”,获取本站PDF版

回复“简历”,获取高质量简历模板

回复“加群”,加入程序员交流群

回复“电子书”,获取程序员类电子书

当前位置: 前端 > javascript高频面试题 > 7.深拷贝与浅拷贝的区别?

浅拷贝:创建一个新的对象,对原始对象的属性值进行拷贝,属性值为基础类型时,则拷贝基础类型的值,属性值为引用类型时,则拷贝引用地址,当二者中有其中一个对引用类型的属性进行修改时,另外一个对象也会受到影响。

深拷贝:将对象完整的拷贝出来,存放在新的内存中,修改二者不会相互影响。

如何实现一个浅拷贝?

(1) Object.assign()

let source = {x:'hello', y:{x:'hi'}}
let target = Object.assign({}, source) // target为生成的浅拷贝对象
target.y.x = 'hello'
console.log(source.y.x) // hello

(2) 展开运算符…

let source = {x:'hello', y:{x:'hi'}}
let target = {... source} // target为生成的浅拷贝对象
target.y.x = 'hello'
console.log(source.y.x) // hello

(3) Array.prototype.concat()

let source = [1, 2, {
    	x:'hi'
	}];
let target = source.concat(); // target为生成的浅拷贝对象
target[2].x = 'hello'
console.log(source[2].x) // hello

(4) Array.prototype.slice()

let source = [1, 2, {
    	x:'hi'
	}];
let target = source.slice(); // target为生成的浅拷贝对象
target[2].x = 'hello'
console.log(source[2].x) // hello

(5) 手写一个浅拷贝

function clone(source) {
    let target = {};
    for (const key in source) {
        target[key] = source[key];
    }
    return target;
};
let source = {x:'hello', y:{x:'hi'}}
let target = clone(source)
target.y.x = 'hello'
console.log(source.y.x) // hello

如何实现一个深拷贝?

(1) JSON.parse(JSON.stringify(source))

let source = {
    a: '1',
    b: 0,
    c: new Date('2020-03-01'),
    d: new RegExp('\\w+'),
    e: new Error(),
    f: undefined,
    g: function () {
    	console.log(1)
    },
    h: NaN,
    i: [1,2,3]
}
let target = JSON.parse(JSON.stringify(source))
console.log(target)
// {
//   "a": "1",
//   "b": 0,
//    "c": "2020-03-01T00:00:00.000Z",
//    "d": {},
//    "e": {},
//    "h": null,
//    "i": [1,2,3]
//  }

JSON.parse(JSON.stringify(source))的缺点:

  • 如果属性值为时间对象,序列化后,时间对象会转换为字符串。
  • 如果属性值为RegExp、Error对象,序列化后,RegExp、Error对象会转换为空对象。
  • 如果属性值为函数,undefined,序列化后,函数, undefined会丢失。
  • 如果属性值为NaN、Infinity和-Infinity,序列化后,则NaN、Infinity和-Infinity会变成null。

(2) 手写一个深拷贝

function deepClone(obj) {
  if (obj === null) return obj; // 如果是null或者undefined就不进行拷贝操作,直接返回
  if (obj instanceof Date) return new Date(obj); // 如果是时间对象,新建一个时间对象返回
  if (obj instanceof RegExp) return new RegExp(obj); // 如果是正则表达式,新建一个正则表达式对象返回
  if (obj instanceof Error) return new Error(obj); // 如果是Error对象,新建一个Error对象返回
  if (typeof obj !== "object") return obj; // 如果是基础类型值或者函数,直接返回
  // 如果是对象递归遍历是,进行深拷贝
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

点击面试手册,获取本站面试手册PDF完整版