网站首页 > 基础教程 正文
在讲不可变数据(Immutable Data)前,先说说可变数据(Mutable Data),在原生js中创建的数据都是可变的,如:
var a = {qty:1}
a.qty = 10;
可能有小伙伴说,可以用const啊,const对基本数据类型还行,但对引用数据类型根本没辙,如
const a = {qty:1}
a.qty = 10;
?
a.qty;// 10
如果把对象a赋值给其它变量还会导致新的问题,如:
const a = {qty:1}
const b = a;
?
a.qty = 10;
?
b.qty;//10
这时你会发现,修改了a,b的值也跟着改了,这其实是js采用引用赋值的方式来实现数据共享的,好处就是节省内存,但缺点也显而易见,稍微不注意就会导致改A坏B的棘手问题,在复杂的项目中,这种问题还不易排查,有诸多安全隐患。
之前的做法是,利用深拷贝的方式来解决这个问题,虽然问题解决了,但又会引发新的问题:浪费内存,还有对一些需要频繁更新数据又有高性能要求的场景(如:React),深拷贝实则为一个不明智的操作,于是,Imutable.js的出现就是要解决这些开发痛点的。
Immutable.js 由Facebook 工程师 Lee Byron 花费 3 年时间打造,在js中的引用赋值可以节省内存,但随着应用的不断复杂后,状态的改变往往会变成噩梦,通常的做法是复制数据来避免被修改,但这样又造成了CPU和内存的消耗,而Immutable利用结构共享可以很好地解决这些问题。
不可变数据:Immutable Data
Immutable Data 是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是对于不需要改变的数据采用结构共享的方式,如下图
<!--  -->
常用数据类型
- List: 有序索引集,类似JS中的Array。
- Map: 无序索引集,类似JS中的Object。
- OrderedMap: 有序的Map,根据数据的set()进行排序。
- Set: 没有重复值的集合。
- OrderedSet: 有序的Set,根据数据的add进行排序。
- Stack: 有序集合,支持使用unshift()和shift()添加和删除。
- Record: 一个用于生成Record实例的类。类似于JavaScript的Object,但是只接收特定字符串为key,具有默认值。
- Seq: 序列,但是可能不能由具体的数据结构支持。
- Collection: 是构建所有数据结构的基类,不可以直接构建。
正如你看到的,immutable.js的数据类型有很多,本文主要介绍比较常用的List和Map,对应于js中的数组和对象。
js与immutable之间的转换
可通过fromJS()和toJS()两个方式实现js和immuatble数据的转换,如:
import Immutable from 'immutable';
const goods = {name:'huawei mate30 pro',price:5998,brand:'huawei'}
?
// js -> immutable data
const imData = Immutable.fromJS(goods)
?
// immutable data -> js
imData.toJS()
但fromJS()和toJS()会深度转换数据,随之带来的开销较大,尽可能避免使用,单层数据转换应直接使用Map()和List()进行转换。另外,还可以直接通过JSON.stringify()对immutable数据转换也json字符串。
import {Map,List} from 'immutable';
?
const initState = Map({
breadcrumb:List([]),
user:Map({}),
manageMenuStatus:false
})
操作immutable数据
获取immutable中的值:get(key)/getIn(keys)
Map 和 List的通用方法,实现如下
import {Map,List} from 'immutable';
let state = Map({
version:'2.0',
user:Map({
username:'laoxie',
age:18,
hobby:List(['代码','电影','唱歌'])
}),
})
?
// 获取 version
state.get('version');// 2.0
?
// 获取username
state.getIn(['user','username']);// laoxie
?
// 获取hobby属性数据
state.getIn(['user','hobby',1]) // 电影
注意: 和传统的js不同,getIn()获取深层深套对象的值时不需要做每一层级的判断是否存在,如不存在则会返回undefined(JS中如果不判空会报错)
- 添加immutable中的数据:set(key,val)/setIn(keys,val)
- 删除属性:delete(key)/deleteIn(keys)
- 更新属性:update(key,val=>newVal)/updateIn(keys,val=>newVal) 如开头所说的,Immutable Data为不可变数据,所有针对immutable的增删改都不会修改原数据,而是返回一个新的值,所以需要给变量重新赋值。
import {Map,List} from 'immutable';
let state = Map({
version:'2.0',
user:Map({
id:'123',
username:'laoxie',
age:18,
hobby:List(['代码','电影','唱歌'])
}),
})
state.set('version','3.0');
state.get('version');//state不被修改,所以还是返回2.0
?
// 正确的修改方式:修改后重新赋值
state = state.setIn(['user','age'],20);
state.getIn(['user','age']);//20
?
// update,delete操作同上
- 判断是否存在某个属性:has(key)/hasIn(keys) 这应该也是实际开发中是比较常用的方法,通过判断属性是否存在来执行不同的操作,如可以判断user.id来判断用户是否登录
if(state.hasIn(['user','id'])){
// 用户已经登录
}else{
// 用户未登录
}
- 判断两个数据是否相等: is(imA,imB) 在JS中,不管是数据还是对象,通过==或===只能判断两个变量的引用地址是否为同一个对象,很难判断两个对象的键值是否相等,与JS不同,immutable是对两个对象的hashCode和valueOf进行比较的
- 数据合并:merge()/mergeDeep() 还有一个比较常用的操作就是合并数据了,在JS我们一般使用Object.assign()来实现,但Object.assign()只能做浅合并,对层级较深的数据可以使用immutable中使用mergeDeep()来实现,两个方法都返回合并后的数据。
const imA = Map({
username:'马云',
money:150000000000,
info:{
married:true,
witticism:'我没见过钱,我对钱不感兴趣'
}
})
const imB = Map({
username:'laoxie',
gender:'男',
info:{
married:false,
age:18,
}
})
const newImData = imA.merge(imB);
console.log(newImData.toJS());
//输出 :
// {
// username:'laoxie',
// gender:'男',
// money:150000000000,
// info:{
// married:false,
// age:18,
// }
// }
const newImData = imA.mergeDeep(imB);
//输出 :
// {
// username:'laoxie',
// gender:'男',
// money:150000000000,
// info:{
// married:false,
// age:18,
// witticism:'我没见过钱,我对钱不感兴趣'
// }
// }
当然Immutable的方法还有很多,本文本只涉及到一引起基本操作,如果想要了解跟多数据类型的操作,请自行查看官网
- 上一篇: js基础面试题92-130道题目 js面试基础知识
- 下一篇: 前端js面试题 前端js面试题 基础
猜你喜欢
- 2024-11-10 JavaScript篇面试题 js 常见面试题
- 2024-11-10 前端js面试题 前端js面试题 基础
- 2024-11-10 js基础面试题92-130道题目 js面试基础知识
- 2024-11-10 javascript基础入门 javascript入门教程
- 2024-11-10 JavaScript 数组元素的一些操作 javascript数组的方法
- 2024-11-10 快速了解JavaScript的基础知识 javascript的理解
- 2024-11-10 web前端JS基础高频面试题 web前端常见面试题及答案(一)
- 2024-11-10 面试宝典:史上最全 Javascript 面试题及答案
- 2024-11-10 JS树结构操作:查找、遍历、筛选、树结构和列表结构相互转换
- 2024-11-10 好程序员web前端培训分享JavaScript学习指南
- 03-12Java程序员Python学习指南(中篇)
- 03-12从IO到NIO:Java数据传输的进阶之路
- 03-12智能库存管理系统:让仓库管理变得简单高效
- 03-12java IO知识体系
- 03-12还不理解 Error 和 Exception 吗,看这篇就够了
- 03-12在Java里如何读取文件
- 03-12FileReader
- 03-12C语言指针专题第11讲:结构体指针
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)