深拷贝和浅拷贝
深拷贝和浅拷贝是经常在面试中会出现的,主要考察你对基本类型和引用类型的理解深度。
一、先了解内存
1. 内存简单划分为堆区域和栈区域
2. 复杂数据类型数据存储在堆区域,基本数据类型变量和引用变量存储在栈区域
二、拷贝- 复制obj对象得到一个全新的对象,
1. 浅拷贝 – 复制的obj对象只复制一层,如果对象属性值是对象则不能复制
2. 深拷贝 – 完全复制的obj对象,如果对象属性值是对象一起复制得到全新对象
3. 示例
[java]const obj = {
name: ‘jack’,
age: 18,
fun: { swiming: ‘游泳’ }, // Object
}
[/java]
浅拷贝
深拷贝
三、实现方式
1. JSON.parse(JSON.stringify(obj))
缺点: 数据类型是Function或数据值为undefined无法拷贝
[java]
const obj = {
name: ‘jack’,
age: 18,
hobby: {swiming:’游泳’},
arr: [{ score: 98 }],
say: () => {}, // Function 无法拷贝
number: undefined, // undefined 无法拷贝
}[/java]
2. Object.assign(obj)或展开运算符{…obj}
缺点:只能拷贝一层,如果属性值是对象,无法拷贝
[java]
const obj = {
name: ‘jack’,
age: 18,
hobby: {swiming:’游泳’}, // Object 无法拷贝
arr: [{ score: 98 }], // Array 无法拷贝
say: () => {}, // Function 无法拷贝
number: undefined, // undefined
}[/java]
3. 递归 cloneDeep()
4. 优化:
- 1. 如果对象属性值没有对象,只有一层,使用展开运算符{…obj}
- 2. 如果对象数据类型不是Function也不是数据值为undefined,使用JSON.parse(JSON.stringify(obj))
- 3. 否则使用递归
四、案例
[java]/**
* 使用 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)
}
[/java]
[java]/**
* 使用 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)
}[/java]
[java]/**
* 深拷貝-递归实现
* @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
}[/java]
[java]/**
* 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)
}[/java]
[java]/**
* 判断对象属性值是否有对象
* @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
}
}
}
}
[/java]
[java]/**
* 递归判断数据类型
* 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])
}
}
}
[/java]
[java]/**
* 拷贝对象 优化方案
* @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)
}
[/java]
[java]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()[/java]
转载请注明来源:深拷贝和浅拷贝




























