关于Immutable.js

前言

在javascript中,对象之间的相互赋值,一般都是对内存地址引用的赋值,也就是不同的变量名可能指向同一块内存区域。
这样的优点就是可以节省内存空间,但是一旦项目趋于复杂,给我们带来的弊端远远大于它的优点。因此,大部分情况下,我们可能会采用深拷贝或者浅拷贝的方式给一个变量赋值,然后改变其内容,但同样这样又会导致内存和性能的浪费。

Immutable.js

通过Immutable.js创建的数据我们称为Immutable Data,Immutable Data一旦创建,就不可再更改,对其进行的添加,修改,删除操作都会生成一个新的Immutable Data。Immutable保证了就数据的可用且不变,同时为了避免深浅拷贝对性能消耗,immatable采用了结构共享,也就是对对象树的一个节点进行修改,只会修改该节点以及该节点的父级,其他节点则进行共享。

Immutable的优缺点

优点

1、降低了可变带来的复杂度

function testFn(){
    let data={type:'string'};
    someFn(data);
    console.log(data)
}

在不查看someFn的代码时,我们是不会知道someFn内部会对data对什么处理,但是如果data是个immutableData的话,那会很明显,data的值是不会发生变化。
2、节省内存
immutable使用结构共享时会尽量做到内存共享,比如下面代码:

import {Map} from 'immutable'

let a=Map({
    name:'testname',
    list:[1,23,4]
});
let b=a.set('name','changeName');

console.log(a===b);//false
console.log(a.get('list')===b.get('list'));//true

3、开发撤销回退功能将会很简单
由于每次修改数据,都会生成一个不同的对象。只需要将每一步操作后的数据存起来,回退的时候取出即可。

缺点

immutable的最大问题是比较容易与js的原生对象混淆,同时许多操作都与js中的处理原生对象的不同,例如immutable中使用map,list分别表示object和array,而在map中获取到值,需要使用

map.get(key)

设定值,需要使用

map.set(key,value)

并且每次修改时都会生成新的对象,按照js的习惯,可能会忘记赋值操作。另外有些第三方库需要使用js的原生对象,可能会忘记进行类型转换。

Immutable.is

两个immutable对象就算值完全一样,存放的内存地址也不一样,因此使用===对比时仍然会输出false。可以使用Immutable.is方法对比。

import {Map,is} from 'immutable'

let a=Map({key1:'1',key2:'2'});
let b=Map({key1:'1',key2:'2'});
console.log(a===b); //false
console.log(is(a,b)); //true

immutable.is比较的是两个对象hashCode或valueOf(javascript对象),由于immutable对象内部采用trie数据结构存储数据,因此只要hashCode一样,对象的值就一样。这样就不需要深度比较,节省了性能。

与react中的shouldComponentUpdate相结合

react中的shouldComponentUpdate生命周期,用来判断是否重新渲染组件,默认都会返回true。我们可以在shouldComponentUpdate周期中利用Immutable.is和===判断是否触发重新render。
代码可以如下

import React, {Component} from 'react';
import {Map,is} from 'immutable'

class App extends Component{
    constructor(props){
        super(props);
    }
    
    shouldComponentUpdate(newProps,newState){
        let thisProps=this.props||{},
            thisState=this.state||{};

        if(Object.keys(newProps).length!==Object.keys(thisProps).length||
            Object.keys(newState).length!==Object.keys(thisState).length
        ){
            return true
        }
		
		//forin循环会遍历出原型链中的属性,因此最好加一个hasOwnProperty判断
        for(const key in newProps){
            if(newProps.hasOwnProperty(key)&&!is(newProps[key],thisProps[key])){
                return true
            }
        }
        for(const key in newState){
            if(newState.hasOwnProperty(key)&&!is(newState[key],thisState[key])){
                return true
            }
        }
        return false
    }
    render(){
        return (
            <div>
                <span>{text}</span>
            </div>
        )
    }
}
export default App

其实为什么不直接这么判断?

if(!is(newProps,thisProps)||!is(newState,thisState)){
	return true
}

实际上,immutable.is同样对深层次数据的判断还是有些乏力
比如

let obj1={key1:'1',key2:'2',key3:'3',arr:[1,2,3]};
let obj2={key1:'1',key2:'2',key3:'3',arr:[1,2,3]};

let a=Map(obj1);
let b=Map(obj2);

console.log(is(a,b));//false

只有引用的对象,指向同一个内存地址,才会为true

let arr=[1,2,3];
let obj1={key1:'1',key2:'2',key3:'3',arr};
let obj2={key1:'1',key2:'2',key3:'3',arr};

let a=Map(obj1);
let b=Map(obj2);

console.log(is(a,b));//true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值