前端面试题 - 对象拷贝方法总结

1. 对象拷贝方法
1.1 JSON.parseJSON.stringify方法 利用JSON.stringifyJSON.parse方法进行的是深拷贝,但无法拷贝函数和undefined,也无法拷贝对象原型链上的属性和方法。

var obj = { a: 1, b: 2, c: { d: 4, // 在解析成 JSON 字符串时,undefined 不解析 e: undefined, // null 在 JSON 字符串中就是 null => "f": null f: null }, f: function () { console.log('function'); } }; var newObj = JSON.parse(JSON.stringify(obj)); console.log(newObj.c.d); // 4 console.log(newObj.e); // undefined console.log(newObj.f); // undefined

1.2 for-in循环 【前端面试题 - 对象拷贝方法总结】利用for-in循环进行的是浅拷贝,只拷贝基本类型的数据,对于引用类型的数据,只复制了指针。
var obj = { a: 1, b: { c: 3 } }; var newObj = {}; for (var key in obj) { newObj[key] = obj[key]; } newObj.b.c = 4; console.log(obj.b.c); // 4 console.log(newObj.b.c); // 4

1.3 Object.assign方法 利用Object.assign方法进行的是浅拷贝,拷贝源对象中的可枚举和自有属性。
var obj = { a: 1, b: { c: 3 } }; var newObj = {}; Object.assign(newObj, obj); newObj.b.c = 4; console.log(obj.b.c); // 4 console.log(newObj.b.c); // 4

1.4 解构赋值 利用解构赋值方法进行的是浅拷贝。
var obj = { a: 1, b: { c: 1 } } var newObj = {...obj} newObj.b.c = 2 console.log(obj.b.c) // 2 console.log(newObj.b.c) // 2

2. 手写对象深拷贝方法
2.1 ES5 实现对象深拷贝
function deepClone (origin, target) { var _tar = target || {}for (var key in origin) { if (origin.hasOwnProperty(key)) { if (typeof origin[key] === 'object' && origin[key] !== null) { _tar[key] = Object.prototype.toString.call(origin[key]) === '[object Array]' ? [] : {}; deepClone(origin[key], _tar[key]); } else _tar[key] = origin[key]; } }return _tar }var obj = { a: 1, b: 2, c: { d: 4, e: 5 }, f: function () { console.log('function'); } }; var newObj = {}; deepClone(obj, newObj); console.log(newObj.c.d); // 4 console.log(newObj.f); // undefined

2.2 ES6 实现对象深拷贝
function deepClone (origin) { if (origin == undefined || typeof origin !== 'object') return origin; if (origin instanceof Date) return new Date(origin); if (origin instanceof RegExp) return new RegExp(origin); const target = new origin.constructor(); for (let key in origin) { if (origin.hasOwnProperty(key)) { target[key] = deepClone(origin[key]); } }return target; }

能够实现对象深拷贝,但当出现循环引用时会导致死循环。因此需要利用WeakMap保存已进行过拷贝的对象,防止死循环。
function deepClone (origin, hashMap = new WeakMap()) { if (origin == undefined || typeof origin !== 'object') return origin; if (origin instanceof Date) return new Date(origin); if (origin instanceof RegExp) return new RegExp(origin); const hashVal = hashMap.get(origin); if (hashVal) return hashVal; const target = new origin.constructor(); hashMap.set(origin, target); for (let key in origin) { if (origin.hasOwnProperty(key)) { target[key] = deepClone(origin[key]); } }return target; }

    推荐阅读