警告
看完文章, 可能会颠覆你的认知!!
语法
Object.assign(target, ...sources)
错误示范
我们都知道 Object.assign()可以实现对象拷贝, 很多人认为他只能实现浅拷贝, 我翻遍了 MDN 的文档, 也没搜索到一个浅字
那么, 到底什么是深拷贝什么是浅拷贝, 你可以去搜索其他文章看看
- let obj = { name: '程序猿', age:{child: 12} }
- let copy = Object.assign({}, obj);
- copy.name = '单身狗'
- copy.age.child = 24
- console.log(obj) // { name: '程序猿', age:{child: 24} }
作者: 拌着生活
链接: https://www.jianshu.com/p/70dc5b968767
來源: 简书
上面的例子大概是这个意思, 有一个原始的 obj 对象, 他里面的 age 对象有一个子节点 child, 然后使用 Object.assign({}, obj)直接拷贝这个对象(或者叫做浅拷贝 obj), 最后用点赋值法修改 copy 对象的属性, 结果是对原 obj 对象也进行了修改
老天, Object.assign 怎么这么烂, 说好的拷贝呢, 只是浅拷贝啊, 那 react 中是不是一大堆 state 都是 N 层结构的对象, 不能用 Object.assign 来玩了呢?
来分析一下它错在哪里了
从语法上来说, 并没有用错, 的确, 这样能实现对象的拷贝, 或者叫做浅拷贝, 但是, 如果要修改对象里面的属性, 就需要用到对象的合并, 也就是下面将要讲到的其实 MDN 上讲的很明白, Object.assign 应该怎样用, 只是大家习惯了看博客
正确使用
看了错误示范, 不用担心, 我带你来正确使用 Object.assign
我也定义一个对象 obj
let obj = {name: '二月', age: {c: 12}}
正确使用 Object.assign 进行对象的拷贝, 通常有 2 种方式
1Object.assign()
我们对要修改的内部对象属性进行单独的赋值, 既不修改 obj, 也不修改新对象 o2, 定义单独的 age 还记得文章开头的语法吗, 源对象...sources 表示支持多个散列的对象
下面的做法相当于, 我们定义了一个新的 age 对象, 将它和 obj 对象进行合并, 然后拷贝给一个空对象{}, 这样使用 Object.assign(), 就不会对原对象 obj 产生影响
- let age = {c: 88}
- let o2 = Object.assign({}, obj, {age})
- console.log(obj, o2)
那么, 有人可能会质疑了, 它只是浅拷贝啊, 就算你取巧实现了拷贝, 但是要是对 o2 进行赋值了咋办, 不也一样会改变 obj 的值?
相信我, 不会的, 别被网上所谓的浅拷贝迷惑了你的眼睛
我紧接着对 o2 里面的 age 进行直接的赋值, 打印出来的 obj 仍旧不受影响, 是不是很神奇!!
- let obj = {name: '二月', age: {c: 12}}
- let age = {c: 88}
- let o2 = Object.assign({}, obj, {age})
- o2.age.c = 66
- console.log(obj, o2)
2ES6 的扩展运算符
现在我们都喜欢用 ES6 的扩展运算符来替换 Object.assign
- let obj = {name: '二月', age: {c: 12}}
- let o1 = {...obj, age: {c: 88}}
- console.log(obj, o1)
同样的, 我把 o1 也用点语法重新赋值看看会不会对 obj 产生影响, 答案当然是不会!
- let obj = {name: '二月', age: {c: 12}}
- let o1 = {...obj, age: {c: 88}}
- o1.age.c = 99
- console.log(obj, o1)
3 分析原理
一切都要从语法说起 Object.assign(target, ...sources), 第一个参数 target 决定了你的对象被拷贝到哪个目标对象上面, 如果你不想对原始对象产生影响, 就定义一个空对象 {} 作为 target, 单单这样还不够, sources 只设置原始对象 obj 的话, 表示对原始对象的浅拷贝, 但是设置多个对象的合并, 就会返回一个全新的对象
总结
看了这篇文章, 你摸着良心问问自己, 真的理解什么是 Object.assign 和扩展运算符了吗? 更深一个层次来看, 你真的理解什么是浅拷贝什么是深拷贝了吗??
补充: 纠结 age 的人是不是没有写过 reducer 啊, 这是一种用 assign 合并对象的思想, age 对象是否变化根本就不是要关心的事情
来源: https://segmentfault.com/a/1190000013167556