深拷贝和浅拷贝

    |     2022年4月23日   |   html/css/js, web前端技术   |     0 条评论   |    1054

深拷贝和浅拷贝是经常在面试中会出现的,主要考察你对基本类型和引用类型的理解深度。

一、先了解内存

1. 内存简单划分为堆区域和栈区域
2. 复杂数据类型数据存储在堆区域,基本数据类型变量和引用变量存储在栈区域

二、拷贝- 复制obj对象得到一个全新的对象,

1. 浅拷贝 – 复制的obj对象只复制一层,如果对象属性值是对象则不能复制
2. 深拷贝 – 完全复制的obj对象,如果对象属性值是对象一起复制得到全新对象
3. 示例

const obj = {
	name: 'jack',
	age: 18,
	fun: { swiming: '游泳' }, // Object
    }
浅拷贝

20220423193220

深拷贝

20220423193605

三、实现方式

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()
转载请注明来源:深拷贝和浅拷贝

上一篇:

下一篇:

回复 取消