前言
我们在学习 React 的过程中经常会碰到一个概念,那就是数据的不可变性(immutable),不可变数据是函数式编程里的重要概念,因为可变数据在提供方便的时候会带了很多棘手的副作用,那么我们应该如何处理这些棘手的问题,如何实现不可变数据呢?
文章目录
- 可变数据的副作用
- 不可变数据的解决方案
- 实现更简单的immutable
1.可变数据的副作用
我们应该都知道的基本知识,在JavaScript中分为原始类型和引用类型.
JavaScript原始类型:Undefined、Null、Boolean、Number、String、Symbol
JavaScript引用类型:Object
同时引用类型在使用过程中经常会产生副作用.
const person = {player: {name: 'Messi'}};
const person1 = person;
console.log(person, person1);
//[ { name: 'Messi' } ] [ { name: 'Messi' } ]
person.player.name = 'Kane';
console.log(person, person1);
//[ { name: 'Kane' } ] [ { name: 'Kane' } ]
复制代码
我们看到,当修改了person
中属性后,person1
的属性值也随之改变,因为这两个变量的指针指向了同一块内存,当一个变量被修改后,内存随之变动,而另一个变量由于指向同一块内存,自然也随之变化了,这就是引用类型的副作用.
可是绝大多数情况下我们并不希望person1
的属性值也发生改变,我们应该如何解决这个问题?
2.不可变数据的解决方案
2.1 浅复制
在ES6中我们可以用Object.assign
或者 ...
对引用类型进行浅复制.
const person = [{name: 'Messi'}];
const person1 = person.map(item =>
({...item, name: 'Kane'})
)
console.log(person, person1);
// [{name: 'Messi'}] [{name: 'Kane'}]
复制代码
person
的确被成功复制了,但是之所以我们称它为浅复制,是因为这种复制只能复制一层,在多层嵌套的情况下依然会出现副作用.
const person = [{name: 'Messi', info: {age: 30}}];
const person1 = person.map(item =>
({...item, name: 'Kane'})
)
console.log(person[0].info === person1[0].info); // true
复制代码
上述代码表明当利用浅复制产生新的person1
后其中嵌套的info
属性依然与原始的person
的info
属性指向同一个堆内存对象,这种情况依然会产生副作用.
我们可以发现浅复制虽然可以解决浅层嵌套的问题,但是依然对多层嵌套的引用类型无能为力.
2.2 深克隆
既然浅复制(克隆)无法解决这个问题,我们自然会想到利用深克隆的方法来实现多层嵌套复制的问题.
我们之前已经讨论过如何实现一个深克隆,在此我们不做深究,深克隆毫无疑问可以解决引用类