Open toFrankie opened 1 year ago
本文更新于 2020-03-03。
PS:这篇别看了,看另外一篇文章:超详细的 JavaScript 深拷贝实现。
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
array.slice()、array.concat()、Object.assign() 都能实现浅拷贝,前两个针对数组。还可以用以下这种方式。
array.slice()
array.concat()
Object.assign()
// 浅拷贝 function shallowCopy(source, target = {}) { for (let key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key] } } return target } let student1 = { name: 'Frankie', age: 22, language: ['Chinese', ['English', 'German']] } let student2 = shallowCopy(student1) student2.language[1] = ['French'] console.log(student1) console.log(student2) // 打印对比可知,language 同时改变了
JSON.stringify
JSON.parse
不足: 无法拷贝对象中的方法属性; 无法拷贝对象中的 undefined 属性
不足:
JQuery 提供的两种方法 $.extend()、$.clone() ,前者是 JS 对象的拷贝、后者是 DOM 对象的拷贝(这里不讨论)
$.extend()
$.clone()
不足: 需要引入 JQuery 库 无法拷贝对象中的 undefined 属性
利用 for..in..、 hasOwnProperty、递归实现
for..in..
hasOwnProperty
递归
不足:比上面的两种方式稍复杂
递归实现深拷贝:
// 假设在 Object 的原型,添加一个 height 属性 Object.prototype.height = 180 // student1 什么类型的属性都有了 const student1 = { name: 'Frankie', age: 22, private: true, friends: ['Mandy', 'John'], abilities: undefined, other: null, car: { color: 'gray', brand: 'Benz' }, teacher: { name: 'Ada', student: ['Helkai', 'Jerry'] }, learn: function () { console.log(this.name + ' is learning JavaScript now.') } } // 深拷贝 function deepCopy(source, target = {}) { for (const key in source) { // for...in... 会遍历原型链上的属性,所以这里需要利用 hasOwnProperty 判断,否则会把 Object 原型上的 height 也拷贝进去了 if (source.hasOwnProperty(key)) { if (typeof source[key] === 'object' && source[key] !== null) { // 判断是否为数组 target[key] = Object.prototype.toString.call(source[key]) === '[object Array]' ? [] : {} // 递归 deepCopy(source[key], target[key]) } else { target[key] = source[key] } } } return target } // 从 student1 中拷贝一个 student2 出来 const student2 = deepCopy(student1) // 修改 student2 的属性值 student2.name = 'Steven' student2.age = 20 student2.car = { color: 'red', brand: 'BMW' } student2.friends[1] = 'Jone' student2.teacher.age = '30' // 打印结果看下面截图,结果是没有相互影响的 console.log(student1) console.log(student2) // JSON 方式 const student3 = JSON.parse(JSON.stringify(student1)) console.log(student3) // 打印 student3 可见 abilities、learn 属性丢失了
日常搬砖选择哪种方式呢,视具体情况而定。我的话,能用 JSON 方式解决的,绝不用递归,没必要复杂化,简单够用即可。但是学习的话,递归的方式必须得懂啊,其实不难懂。
其实还有优化的空间,我们都知道 for...in 的性能是比较差的。关于性能优化篇,可以看下掘金某大神的文章,这里。
The end.
本文更新于 2020-03-03。
什么是深浅拷贝?
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
浅拷贝的几种方式
array.slice()
、array.concat()
、Object.assign()
都能实现浅拷贝,前两个针对数组。还可以用以下这种方式。深拷贝的几种方式
JSON.stringify
&JSON.parse
方法JQuery 提供的两种方法
$.extend()
、$.clone()
,前者是 JS 对象的拷贝、后者是 DOM 对象的拷贝(这里不讨论)利用
for..in..
、hasOwnProperty
、递归
实现递归实现深拷贝:
运行结果
日常搬砖选择哪种方式呢,视具体情况而定。我的话,能用 JSON 方式解决的,绝不用递归,没必要复杂化,简单够用即可。但是学习的话,递归的方式必须得懂啊,其实不难懂。
其实还有优化的空间,我们都知道 for...in 的性能是比较差的。关于性能优化篇,可以看下掘金某大神的文章,这里。
The end.