欢迎访问我的博客https://qqqww.com,祝码农同胞们早日走上人生巅峰,迎娶白富美~~~
看这个深拷贝和浅拷贝之前,先要对javascript中不同数据类型之间的传值有一定的了解
javascript中不同数据类型之间的传值
javascript
中数据类型简单分为基本数据类型和引用数据类型基本数据类型:String,Number,Boolean等
引用数据类型:Array,Object等
基本数据类型和引用数据类型最大的区别在于他们的处安置方式不同
基本数据类型的传值:
var a = 1
var b = a
// a = 1
// b = 1
b = 2
// a = 1
// b = 2
// a 的原始值不会被修改
引用数据类型的传值:
var people = {
name: 'zhangsan',
age: 10
}
var people2 = people
console.log(people.age) // 10
console.log(people2.age) // 10
people2.age = 100
console.log(people.age) // 100
console.log(people2.age) // 100
// people 的值被修改了
这里发现 people
的值被修改了,因为这就是引用传值,他们本身指向了同一个引用,即地址,修改的是同一个地址中的值,所以会发生想修改people2
的时候,却无意间影响到了people
的原始值,这就是浅拷贝
深拷贝和浅拷贝
如上例子,简单粗暴的理解就是当people2
复制了people
,而当people2
修改时,people
一块被修改了,这叫浅拷贝,当people2
修改时,而people
没有被修改,这叫深拷贝
但是,本意不想修改people
,只想修改people2
的,却造成了这样的错误,如何避免呢?
var people = {
name: 'zhangsan',
age: 10
}
var people2 = {
name: people.name,
age: people.age
}
var people2 = people
console.log(people.age) // 10
console.log(people2.age) // 10
people2.age = 100
console.log(people.age) // 10
console.log(people2.age) // 100
// people 的值没有被修改
这个时候是深拷贝,但是总不能总不能这么复杂吧,要一个一个的拷贝到people2
对象中,很麻烦,容易出错,这时候就要有深拷贝的方法和浅拷贝的方法
浅拷贝的实现
-
赋值,上面介绍传值的时候也有的方法,就是直接赋值的操作,可以参照上面的例子
-
Object.assign()
-
介绍:
Object.assign
是ES6
的新函数,Object.assign()
方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象,但是Object.assign()
进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身 -
语法:
Object.assign(target, ...sources)
-
参数:
target
:目标对象,sources
:任意多个源对象 - 返回值:返回目标对象
var people = { name: 'zhangsan', age: 10, zhangsan: { say: function () { console.log('hello') }, height: 180 } } var people2 = Object.assign({}, people) console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 180 people2.zhangsan.height = 181 console.log(people.zhangsan.height) // 181 console.log(people2.zhangsan.height) // 181 // people 的值被修改了
但是当
Object.assign()
去处理只有一层的拷贝的时候,再看看var people = { name: 'zhangsan', age: 10 } var people2 = Object.assign({}, people) console.log(people.age) // 10 console.log(people2.age) // 10 people2.age = 100 console.log(people.age) // 10 console.log(people2.age) // 100 // people 的值没有被修改
总结:
当
Object.assign()
去处理一层的拷贝的时候,可以达到,修改people2
不影响people
,但是当Object.assign()
进行深一层的拷贝的时候,修改people2
会影响people
-
介绍:
深拷贝的实现
- 手动复制,这在上面介绍传值的时候,有过例子,可以参照上面的例子,缺点:很麻烦
- 对象只有一层的话,可以用上面的
Object.assign()
去处理 - 利用
JSON
字符串的基本类型赋值- 优点:理解简单,用起来也简单
-
缺点:只适用于那些能够被 json 直接表示的数据结构,且它会抛弃对象的
constructor
var people = { zhangsan: { age: 10 } }
var people2 = JSON.parse(JSON.stringify(people))
console.log(people.zhangsan.age) // 10
console.log(people2.zhangsan.age) // 10
people2.zhangsan.age = 100
console.log(people.zhangsan.age) // 10
console.log(people2.zhangsan.age) // 100
// people.zhangsan.age 原始值没被修改
- 递归拷贝
function deepClone(a, b) {
var obj = b || {}
for (var i in a) {
if (typeof a[i] === 'object') {
obj[i] = (a[i].constructor === Array) ? [] : {}
arguments.callee(a[i], obj[i])
} else {
obj[i] = a[i]
}
}
return obj
}
var str = {}
var obj = { a: {a: "hello", b: 21} }
deepClone(obj, str)
console.log(str.a)
上述方法已经能够实现,深拷贝,但是当两个对象相互引用的时候,问题就来了,会出现死循环
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环
改进如下:
function deepClone(a, b) {
var obj = b || {}
for (var i in a) {
var prop = a[i] // 避免相互引用对象导致死循环,如a.a = a的情况
if(prop === obj) { // 避免相互引用对象导致死循环,如a.a = a的情况
continue
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {}
arguments.callee(prop, obj[i])
} else {
obj[i] = prop
}
}
return obj
}
var str = {}
var obj = { a: {a: "hello", b: 21} }
deepClone(obj, str)
console.log(str.a)
- 使用Object.create()方法
Object.create()方法的原理其实就和上面递归拷贝实现改进版是一样的
var people = {
name: 'zhangsan',
age: 10,
zhangsan: {
say: function () {
console.log('hello')
},
height: 180
}
}
var people2 = Object.create(people)
console.log(people.zhangsan.height) // 180
console.log(people2.zhangsan.height) // 180
people2.zhangsan.height = 181
console.log(people.zhangsan.height) // 180
console.log(people2.zhangsan.height) // 181
// people 的值没被修改
- JQuery 中的 $.extend
var $ = require('jquery')
var people = {
name: 'zhangsan',
age: 10,
zhangsan: {
say: function () {
console.log('hello')
},
height: 180
}
}
var people2 = $.extend(true, {}, people)
console.log(people.zhangsan.height) // 180
console.log(people2.zhangsan.height) // 180
people2.zhangsan.height = 181
console.log(people.zhangsan.height) // 180
console.log(people2.zhangsan.height) // 181
// people 的值没被修改
网友评论