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

相关推荐
看到请催我学习20 分钟前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
XiaoYu20022 小时前
22.JS高级-ES6之Symbol类型与Set、Map数据结构
前端·javascript·代码规范
儒雅的烤地瓜2 小时前
JS | JS中判断数组的6种方法,你知道几个?
javascript·instanceof·判断数组·数组方法·isarray·isprototypeof
道爷我悟了2 小时前
Vue入门-指令学习-v-on
javascript·vue.js·学习
27669582922 小时前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
PleaSure乐事2 小时前
【Node.js】内置模块FileSystem的保姆级入门讲解
javascript·node.js·es6·filesystem
雷特IT3 小时前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript
awonw3 小时前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
老齐谈电商3 小时前
Electron桌面应用打包现有的vue项目
javascript·vue.js·electron
柏箱4 小时前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css