js-深拷贝(完整版)

187 阅读1分钟
// 简单版
const obj = {
	name: 'jjj',
	age: 22,
	friends: {
		name: 'lll',
		age: 23
	},
	hobbies: ['music', 'basketball', 'game']
}

const deepClone = (target) => {
	// 基本类型直接返回
	if(typeof target !== 'object' || target == null){
		return target
	}
	// 判断是否为对象
	let newObj = Array.isArray(target) ? [] : {}
	for(let key in target) {
		// 忽略原型上的属性
		if(target.hasOwnProperty(key)) {
			newObj[key] = typeof target[key] === 'object' ? deepClone(target[key]) : target[key]
		}
	}
	return newObj
}

const cloneObj = deepClone(obj)
obj.friends.name = 'aaa'
obj.hobbies.push('code') 
console.log(obj)
console.log(cloneObj)
// 完整版
// 完整版
let symbolStr = Symbol('symbolStr') // 参数只是用来描述该Symbol
console.log(symbolStr.description ); // 查看描述
console.log(symbolStr.toString()); // 查看描述
console.log(String(symbolStr)); // 查看描述

let map = new Map()
map.set('', 'String')
map.set('{}', {name: 'map'})
map.set('[]', [1,2,3,3])

let symbolObj = Symbol('symbolObj')
const obj = {
	name: 'maker',
	age: 22,
	friends: {
		name: 'lll',
		age: 23
	},
	hobbies: ['music', 'basketball', 'game'],
  exercise: function () {
    console.log(this.name + '在运动!');
  },
  // 在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中。
  [symbolStr]: 'symbolStr',
  [symbolObj]: {
    name: 'symbolObj',
    age: 0
  },
  set: new Set([1,2,3,4,4]),
  map: map
}

const deepClone = (target,hash= new WeakMap()) => {
	// 基本类型直接返回
	if(typeof target !== 'object' || target == null){
		return target
	}
	// 判断是否是一个Set类型
	if(target instanceof Set) {
		return new Set([...target])
	}
	// 判断是否是一个Map类型
	if(target instanceof Map) {
		return new Map([...target])
	}
	 // 如果是一个函数类型,直接使用同一个函数
  if (typeof target === "function") {
    return target;
  }
	// 避免重复克隆
	if(hash.has(target)) {
		return has.get(target)
	}
	// 判断是否为数组
	let newObj = Array.isArray(target) ? [] : {}

	hash.set(target, newObj)

	// 针对Symbols的key处理(key也可以不一样)
	const symKeys = Object.getOwnPropertySymbols(target)
	if(symKeys.length) {
		symKeys.forEach((sKeys) => {
			if(typeof target[sKeys] === 'object' && target !== null) {
			newObj[sKeys] = deepClone(target[sKeys], hash)
			} else {
				newObj[sKeys] = target[sKeys]
			}
		})
	}

	for(let key in target) {
		// 忽略原型上的属性
		if(target.hasOwnProperty(key)) {
			newObj[key] = typeof target[key] === 'object' ? deepClone(target[key], hash) : target[key]
		}
	}
	return newObj
}

const cloneObj = deepClone(obj)
cloneObj.name = 'cloner'
cloneObj.friends.name = 'robot'
cloneObj.hobbies.push('study')
cloneObj[symbolStr] = 'cloneSym'
cloneObj[symbolObj].age = 2
cloneObj.set.add(5)
cloneObj.set.add(5)
cloneObj.map.set('{}', {name: 'newMapObj'})
console.log(obj)
console.log(cloneObj)
obj.exercise()
cloneObj.exercise()