深拷贝和浅拷贝
深拷贝和浅拷贝是经常在面试中会出现的,主要考察你对基本类型和引用类型的理解深度。
一、先了解内存
1. 内存简单划分为堆区域和栈区域
2. 复杂数据类型数据存储在堆区域,基本数据类型变量和引用变量存储在栈区域
二、拷贝- 复制obj对象得到一个全新的对象,
1. 浅拷贝 – 复制的obj对象只复制一层,如果对象属性值是对象则不能复制
2. 深拷贝 – 完全复制的obj对象,如果对象属性值是对象一起复制得到全新对象
3. 示例
const obj = { name: 'jack', age: 18, fun: { swiming: '游泳' }, // Object }
浅拷贝
深拷贝
三、实现方式
1. JSON.parse(JSON.stringify(obj))
缺点: 数据类型是Function或数据值为undefined无法拷贝
const obj = { name: 'jack', age: 18, hobby: {swiming:'游泳'}, arr: [{ score: 98 }], say: () => {}, // Function 无法拷贝 number: undefined, // undefined 无法拷贝 }
2. Object.assign(obj)或展开运算符{…obj}
缺点:只能拷贝一层,如果属性值是对象,无法拷贝
const obj = { name: 'jack', age: 18, hobby: {swiming:'游泳'}, // Object 无法拷贝 arr: [{ score: 98 }], // Array 无法拷贝 say: () => {}, // Function 无法拷贝 number: undefined, // undefined }
3. 递归 cloneDeep()
4. 优化:
- 1. 如果对象属性值没有对象,只有一层,使用展开运算符{…obj}
- 2. 如果对象数据类型不是Function也不是数据值为undefined,使用JSON.parse(JSON.stringify(obj))
- 3. 否则使用递归
四、案例
/** * 使用 JSON.parse(JSON.stringify(obj)) 拷贝 */ const testJSON = () => { const obj = { name: 'jack', age: 18, hobby: { swiming: '游泳' }, // Object arr: [{ score: 98 }], // Array say: () => {}, //Function number: undefined, //undefined } const cloneObj = JSON.parse(JSON.stringify(obj)) console.log('obj :', obj, '\n cloneObj :', cloneObj) }
/** * 使用 1. Object.assign(obj) * 2. 展开运算符{...obj} */ const testAssign = () => { const obj = { name: 'jack', age: 18, hobby: { swiming: '游泳' }, // Object arr: [{ score: 98 }], // Array say: () => {console.log('say>>')}, //Function number: undefined, //undefined } // const cloneObj = Object.assign(obj) const cloneObj = { ...obj } cloneObj.name = 'rose' cloneObj.age = 20 cloneObj.hobby.swiming = '不会游泳' // 无法拷贝,cloneObj.hobby == obj.hobby cloneObj.arr[0].score = 100 cloneObj.say() console.log('obj :', obj, '\n cloneObj :', cloneObj) }
/** * 深拷貝-递归实现 * @param {*} data * @returns */ const cloneDeep = data => { const newData = Array.isArray(data) ? [] : {} for (let key in data) { if (data[key] && typeof data[key] === 'object') { newData[key] = cloneDeep(data[key]) } else { newData[key] = data[key] } } return newData }
/** * test递归-拷贝 */ const testCloneDeep = () => { const obj = { name: 'jack', age: 18, hobby: { swiming: '游泳' }, // Object arr: [{ score: 98 }], say: () => {}, //Function number: undefined, //undefined students: [ { student: { num: { id: 1, }, }, }, ], } const cloneObj = cloneDeep(obj) cloneObj.name = 'rose' cloneObj.age = 20 cloneObj.hobby.swiming = '不会游泳' cloneObj.arr[0].score = 100 cloneObj.students[0].student.num.id = 100 console.log('obj :', obj, '\n cloneObj :', cloneObj) console.log(cloneObj.students[0].student.num.id === obj.students[0].student.num.id) }
/** * 判断对象属性值是否有对象 * @param {} data * @returns */ const isObjectValue = data => { for (let key in data) { if (data[key] && typeof data[key] === 'object') { if(Object.prototype.toString.call(data[key]) !== '[object Function]'){ return true } } } }
/** * 递归判断数据类型 * Function或undefined返回为true */ const isFunctionOrUndefined = data => { for (let key in data) { if (data[key] === undefined) { return true } else if (data[key] && Object.prototype.toString.call(data[key]) === '[object Function]') { return true //Function } else if (data[key] && typeof data[key] === 'object') { isFunctionOrUndefined(data[key]) } } }
/** * 拷贝对象 优化方案 * @param {*} obj 原对象 * @param {*} cloneOjb 返回拷贝对象 */ const cloneDeepObj = obj => { if (obj === undefined) { throw new TypeError('param is not undefined') } //判断拷贝对象只有一层及属性值都不是对象,使用Object.assign() if (!isObjectValue(obj)) { return { ...obj } } //判断类型,如果不是Function或undefined使用JSON方式 if (!isFunctionOrUndefined(obj)) { return JSON.parse(JSON.stringify(obj)) } return cloneDeep(obj) }
const testCloneDeepObj = () => { const obj = { name: 'jack', age: 18, hobby: { swiming: '游泳' }, arr: [{ score: 98 }], say: function(){console.log(this.name)}, number: undefined, } const cloneObj = cloneDeepObj(obj) cloneObj.name = 'rose' cloneObj.age = 20 cloneObj.hobby.swiming = '不会游泳' cloneObj.arr[0].score = 100 console.log('obj :', obj, '\n cloneObj :', cloneObj) cloneObj.say() obj.say() } testCloneDeepObj()
转载请注明来源:深拷贝和浅拷贝