一文看懂JS的强拷贝和深拷贝

前言

有些易混的点确实需要拿出来好好数落一下。拷贝就是一个必须要盘点的问题。

应用

首先看看啥时候会用到拷贝。简单地说,拷贝可以说是无处不在,甚至我们最熟悉的圆形操作都是在不断地拷贝。更实际一点,拿React来说,如果你对拷贝理解不清的话,类组件形式的React你是没法写的,虽说函数组件出现之后这种情况好了许多,但是Redux这个东西你还是逃不了的,不了解拷贝你甚至都看不懂Redux的写法。

在这里,关于应用类似和值类型这里就不多说了,这些是看懂这篇文章的基础。

浅拷贝

但是赋值是要说一下的。

let a = [1,2]
let b = a
a===b

我们都知道上面的运算是true的,也就是赋值只会把栈的引用赋值出去,并不会赋值引用的堆中的数据。

而浅拷贝虽然可以复制一个新的对象,但是如果对象中又存在引用类型的话,他是无能为力的:

> let a = {name: 's',age: 2,fir:{first: '2',second:'3'}}
undefined
> a
{ name: 's', age: 2, fir: { first: '2', second: '3' } }
> let b = a
undefined
> b.fir.first = '4'
'4'
> a
{ name: 's', age: 2, fir: { first: '4', second: '3' } }
> let c = Object.assign({},a)
undefined
> c
{ name: 's', age: 2, fir: { first: '4', second: '3' } }
> c.name = 'd'
'd'
> c
{ name: 'd', age: 2, fir: { first: '4', second: '3' } }
> a
{ name: 's', age: 2, fir: { first: '4', second: '3' } }
> c.fir.first = '5'
'5'
> c
{ name: 'd', age: 2, fir: { first: '5', second: '3' } }
> a
{ name: 's', age: 2, fir: { first: '5', second: '3' } }

可以看出,当我们改变c中fir的first值后,a中的该值也发生了改变。

这是因为我们使用的浅拷贝,即Object.assign,包括concat和slice方法,执行的都是浅拷贝。

深拷贝

对于深拷贝,大家最熟悉的就是JSON.stringify和JSON.parse。

> b = JSON.stringify(a)
'{"name":"s","age":2,"fir":{"first":"5","second":"3"}}'
> c = JSON.parse(b)
{ name: 's', age: 2, fir: { first: '5', second: '3' } }
> a
{ name: 's', age: 2, fir: { first: '5', second: '3' } }
> a.fir.first = '6'
'6'
> a
{ name: 's', age: 2, fir: { first: '6', second: '3' } }
> c
{ name: 's', age: 2, fir: { first: '5', second: '3' } }

如果不使用immutable.js或者immer的话,这种方式是我们写Redux中最常用的。

插个题外话,这里有个工具是用来查看immutable数据的,我们知道immutable最大的缺点就是难以调试,有这个的话会方便很多。

扫描二维码关注公众号,回复: 8704212 查看本文章

咳咳扯远了,那么Redux为什么需要深拷贝的数据呢?

Redux 和 React-Redux 都使用了浅比较。具体来说:
Redux 的 combineReducers 方法 浅比较 它调用的 reducer 的引用是否发生变化。
React-Redux 的 connect 方法生成的组件通过 浅比较根 state 的引用变化 与 mapStateToProps 函数的返回值,来判断包装的组件是否需要重新渲染。 以上浅比较需要不变性才能正常工作

因此,深拷贝或者immutable就是很需要的了,所以如果你不理解这个概念,很多东西是做不了的。

发布了346 篇原创文章 · 获赞 330 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43870742/article/details/103969834