Object.assign() 是一种浅拷贝
let target = {}
let source = {
a: 1,
b: 2
}
Object.assign(target, source)
console.log('target', target)
对象的结构复杂化后
let target = {
a: 1,
b: {
f: 5,
g: 6
}
}
let source = {
a: 1,
b: {
c: {
d: 2,
},
g: 6
}
}
Object.assign(target, source)
console.log('target', target)
返回的数据中可以看出, source 对象新增数据到 target 中没有问题,但是深层的属性,容易被消除,比如target 对象 中的 b 属性下的 f 属性 在 拷贝后消失了。这说明 Object.assign() 存在一定的缺陷,或可以称之为 浅拷贝
Object.assign() 可以轻易的将 基本的数据类型 拷贝,但是对于 对象这样的引用数据类型则是直接将 引用地址赋值过去,这样就会导致 目标对象 数据的 破坏
浅拷贝与深拷贝的区别
浅拷贝对于 引用类型 是仅仅赋值其内存地址,其中一个对象值发生改变,拷贝的目标对象也会相应的改变,但是深拷贝,就不会产生影响
let person = {
name: '潜龙',
age: 34
}
let person2 = person
console.log('person',person)
console.log('person2', person2)
person.age = 18
console.log('person2', person2)
这里的 person2 就是 浅拷贝的 person对象的内容, 所以当 person 对象的 age属性发生改变的时候,person2 中的 age 属性也会一起改变
如何实现 深拷贝
JSON.parse()&JSON.stringify()
JSON 的本质 就是一个字符串
JSON.parse()
将 json 格式的字符串 转化成 对象
JSON.stringify()
将 对象 转化成 json 字符串
let person = {
name: '潜龙',
age: 34
}
let str = JSON.stringify(person)
console.log('str', str);
let obj = JSON.parse(str);
console.log('obj', obj)
从这段代码可以看出, str 所表示的 数据只是一个字符串,是无法展开的
实现深拷贝
let obj1 = {
name: '潜龙',
age: 24
}
let str = JSON.stringify(obj1)
let obj2 = JSON.parse(str);
console.log('obj2',obj2)
obj1.age = 18
console.log('obj1', obj1)
console.log('obj2', obj2)
从这段代码可以看出,obj1 与 obj2 之间 属性值的改变是互不干扰的,达到了 深拷贝的目标
typeof
typeof 方法 判断数据类型的时候,存在一定的缺陷,typeof 可以用来判断基本数据类型,但是判断 引用数据类型的时候就会统一返回 object, 这样我们就没办法区分 数组和 对象了
let num = 1
let str = '1'
let flag = true
let obj = {}
let arr = []
console.log(typeof num);
console.log(typeof str);
console.log(typeof flag);
console.log(typeof obj)
console.log(typeof arr);
数组与对象类型区分检查方案
针对 typeof 无法区分 object 与 array 之间的区别
这里主要使用 Object.prototype.toString 方法进行区分
console.log('对象',Object.prototype.toString.call({}))
console.log('数组', Object.prototype.toString.call([]))
从这里我们可以看出 最后一个单词 帮我们区分出了 引用数据 的 确切类型, 为了方便判断我们可以使用 Stirng 的 分割 方法 slice()
let checkType = data => {
let string = Object.prototype.toString.call(data)
const type = string.slice(8, -1);
return type
};
console.log('对象' ,checkType({}))
console.log('数组', checkType([]))
定义深拷贝方法
这里判断 变量的 类型到底是 数组还是 对象的原因是 方便创建 对象的初始值的数据类型
// 引用类型数据下,判断是数组还是对象
let checkType = data => {
let string = Object.prototype.toString.call(data)
const type = string.slice(8, -1);
return type
};
// 深拷贝方法
let deepClone = target => {
let targetType = checkType(target);
let result
// 这里只处理 引用类型, 如果是基本类型 则直接返回
if (targetType === 'Object') {
result = {};
} else if (targetType === 'Array') {
result = [];
} else {
return target;
}
for (let key in target) {
let value = target[key]
let valueType = checkType(value)
if (valueType === 'Object' || valueType === 'Array') {
// 如果数据仍然是 引用类型 则 进行递归处理
result[key] = deepClone(value)
} else {
// 如果 value 是基本类型 则结束递归,直接赋值
result[key] = value
}
}
return result
};
测试数组
let arr1 = [1, 2, {age: 24}];
console.log('arr1', arr1)
let arr2 = deepClone(arr1);
console.log('arr2', arr2);
arr1[2].age = 18;
console.log('arr2', arr2)
当我们改变 arr1 的 值以后,arr2 没有受到影响表示,深拷贝成功
测试对象
let obj1 = {
name: '潜龙',
hobby: ['coding', 'eating']
}
let obj2 = deepClone(obj1);
obj1.hobby[0] = 'sleeping';
console.log('obj1', obj1);
console.log('obj2', obj2);