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的想法了

相关推荐
早點睡3903 分钟前
ReactNative项目OpenHarmony三方库集成实战:react-native-snackbar
javascript·react native·react.js
研來如此1 小时前
C++ 接口设计 && Doxygen 注释
前端·javascript·c++
野槐2 小时前
Electron开发
前端·javascript·electron
天真萌泪9 小时前
JS逆向自用
开发语言·javascript·ecmascript
柳杉10 小时前
震惊!字符串还能这么玩!
前端·javascript
仍然.10 小时前
算法题目---模拟
java·javascript·算法
我命由我1234512 小时前
React - 类组件 setState 的 2 种写法、LazyLoad、useState
前端·javascript·react.js·html·ecmascript·html5·js
聊聊MES那点事12 小时前
JavaScript图表控件AG Charts使用教程:使用AG Charts React实时更新柱状图
开发语言·javascript·react.js·图表控件
斯班奇的好朋友阿法法13 小时前
离线ollama导入Qwen3.5-9B.Q8_0.gguf模型
开发语言·前端·javascript
莫物14 小时前
vue过滤表格数据导致的索引错乱问题
前端·javascript·vue.js