immutable.js 不可变数据

immutable.js 不可变数据

js中的对象和数组属于引用数据类型,一个对象赋值给另外一个对象,其实是引用地址的赋值,两个变量同时指向同一个对象。

如果需要进行修改对象,那么两个对象会同时改变,

什么是不可变

对引用数据进行改变的时候,不会更改原数据,而是返回一个新的数据

通过...进行创建,这是一个浅拷贝

js 复制代码
const arr1 = [1,2,3]
const arr2 = [...arr1]
arr2.push(4) // arr2[1,2,3,4] arr1[1,2,3]

如果需要进行多层的,那么会失效,需要使用深拷贝

ini 复制代码
const arr1 = [{a:2},2,3]
const arr2 = [...arr1]
arr2[0].a = 1 // arr2[{a:1},2,3,4] arr1[{a:1},2,3]

深拷贝存在性能问题,每次深拷贝需要对对象递归复制,内存多出了很多重复相同数据,增加内存占用

简单的深拷贝实现

js 复制代码
/**
 * @description 深拷贝
 * */

function deepClone(obj, map = new WeakMap()) {

    // 判断基础类型
    if (typeof obj !== "object" || obj == null) return obj;
    // 解决循环引用
    if (map.has(obj)) return map.get(obj);
    let target = {};
    map.set(obj, target);
    // 判断Map
    if (obj instanceof Map) {
        target = new Map();
        obj.forEach((v, k) => {
            const k1 = deepClone(k, map);
            const v1 = deepClone(k, map);
            target.set(k1, v1);
        });
    }
    // 判断Set
    if (obj instanceof Set) {
        target = new Set();
        obj.forEach(v => {
            target.add(deepClone(v, map));
        });
    }

    // 判断array
    if (obj instanceof Array) {
        target = obj.map(item => deepClone(item,map));
    }
    // 判断Object
    for (let key in obj) {
        target[key] = deepClone(obj[key],map);
    }
    return target;
}

优点

  • 可以防止数据突变带来的不可预测。

  • 可以提高操作性能

使用方法

提供了多个数据结构,常用的是List和Map

设置数据(set)

js 复制代码
import { List, Map } from "immutable"

const l1 = new List(["a","b"])
const l2 = l1.set(0,"c") // List["c","b"]

const m1 = new List({a:1,b:2})
const l2 = l1.set("a",3) // Map{a:3,b:2}

获取数据(get)

js 复制代码
import { List, Map } from "immutable"

const l1 = new List(["a","b"])
const l2 = l1.set(0,"c") // List["c","b"]
l1.get(0) // a
const m1 = new List({a:1,b:2})
const m2 = l1.set("a",3) // Map{a:3,b:2}
m2.get("a") // 3

合并数据(merge)

js 复制代码
import { List } from "immutable"

const l1 = new List(["a","b"]) // ["a","b"]
const l2 = l1.set(0,"c") // List["c","b"]
const l3 = l1.merge(l2) // List ["a","b","c","b"]

const m1 = new Map({a:1,b:2})// Map{a:1,b:2}
const m2 = new Map({c:3,d:4})// Map{c:1,d:2}
const l3 = m1.merge(m2) // // Map{a:1,b:2,c:1,d:2}

删除数据(remove)

js 复制代码
const l1 = new List(["a","b"]) // ["a","b"]
const l2 = l1.set(0,"c") // List["c","b"]
l2.remove(0) // List["b"]

更新(update)

js 复制代码
const l1 = new List(["a","b"]) // ["a","b"]
const l2 = l1.set(0,"c") // List["c","b"]
l2.update(0,target => target+1)  // // List["c1","b"]

const m1 = new Map({a:1,b:2})// Map{a:1,b:2}
m1.update("a", target => target*2 ) //  Map{a:2,b:2}

数据转换(fromJs)

不支持嵌套,需要转换

js 复制代码
import { fromJs, Map } from "immutable"
const m1 = new Map({a:{b:{c:1}}}) // Map{a:[object Obejct]}
const m2 = fromJs({a:{b:{c:1}}}) // Map({a:{b:{c:1}}})
const m3 = m2.setIn(["a","b","c"],100) // Map({a:{b:{c:100}}})

数据比较(is)

判断不可变数据是否相等

js 复制代码
import { fromJs, is } from "immutable"
const m1 = fromJs({a:{b:{c:1}}}) // Map({a:{b:{c:1}}})
const m2 = m2.setIn({a:{b:{c:1}}}) // Map({a:{b:{c:100}}})

和react结合

react中更新数据需要用到不可变数据,内部使用Object.is判断两个对象是否相同,如果不相同,那么就会进入diff过程

jsx 复制代码
import { fromJs,is } from "immutable"
class App extends Component {
  constructor() {
    super()
    this.updateName = this.updateName.bind(this)
    this.state ={
      person:fromJs({name:"张三"})
    } 
  }
  shouldComponentUpdate(nextProps,nextState) {
    return !is(this.state.person,nextState.person)
  }
  updateName() {
    this.setState({
      person:this.state.person.set("name","李四")
    })
  }
  render() {
    console.log("render")
    return (	<div>
            	<p>{this.state.person.get("name")}</p>
              <button onClick={this.updateName}>修改</button>
           	</div>)
  }
}

结尾

@react/toolkit内部集成了不可变数据库,有必要学习和认识一下。

我认为简单的数据正常使用扩展运算符就可以解决,至于是否需要使用immutable这个库。取决于大leader的想法了

相关推荐
A24207349302 分钟前
js模糊搜索
开发语言·javascript·ecmascript
J2虾虾6 分钟前
关于Ant Design Vue
前端·javascript·vue.js
程序员笨鸟13 分钟前
[特殊字符] React 高频 useEffect 导致页面崩溃的真实案例:从根因排查到彻底优化
前端·javascript·学习·react.js·面试·前端框架
普通网友13 分钟前
框架适配:React/Vue 项目中如何高效使用 debugger 断点
javascript·vue.js·react.js
Shriley_X14 分钟前
React
javascript·react.js·ecmascript
写代码的【黑咖啡】15 分钟前
Python 中的控制流程:掌握程序的逻辑跳转
服务器·javascript·python
西瓜凉了半个夏~17 分钟前
React专题:react,redux以及react-redux常见一些面试题
前端·javascript·react.js
GISer_Jing30 分钟前
前端开发:提示词驱动的全链路
前端·javascript·aigc
多看书少吃饭39 分钟前
Electron 桌面应用打开录音功能导致页面蓝屏问题解决方案
javascript·electron·策略模式
编程猪猪侠42 分钟前
手写js轮播图效果参考
开发语言·javascript·ecmascript