immutable实现深浅拷贝

 immutable实现深浅拷贝

我们都知道在Redux里面在prevstate 与newData之间赋值的时候要实现深拷贝,之前的时候我们都通过const newData = JSON.parse(JSON.stringify(prevState));来实现深拷贝,但是我们知道这个方法太消耗性能,所以我们可以使用node自带的Api lodash

lodsh 用法

需要先npm i lodsh

const  { cloneDeep } = require("lodash");
const state = {
  str: "韩梅梅",
  obj: { x: 1 },
  arr: [1, 2, 3],
};
const newState = cloneDeep(state)
console.log(newState === state)//这个地方就是用了loadsh里面的cloneDeep方法实现了深拷贝

immutable用法

 Documentation v4.1.0 — Immutable.js 官网

首先来看下immutable的定义

不可变数据 数据一旦被创建就不修改

 对immutable数据做操作的时候都会返回一个新的immutable对象, 修改对象的值和原值一样 相当于是没修改

优缺点

优点

  节省内存 优化代码 深拷贝          函数式编程        可以溯源,所有改变数据的操作都会记录

缺点

需要学习新的api           容易和原生的api混淆            需要引入第三方库

immutable用法

首先需要下载依赖  npm i immutable

然后再node里面用的时候

下面是把immutable里面我们用到的方法进行解构出来我们挨个解释

const { Map, List, Seq, fromJS, Set, is } = require("immutable");

Map

首先map是用来深拷贝对象的

set,get方法

例如:

const map1 = Map({//这里是把对象放到Map里面
  a:1,
  b:2,
  c:3
})
const map2 = map1.set("a",4) //这里是把map1里的a属性改成4在赋值给map2,这里map1是不变的,但是map2的a就是4了
console.log(map1.get('a'),map2.get('a'))//1,4
console.log(map1 === map2) //false

但是如果是下面这样的话
const map2 = map1.set("a",1) ,map1里面的a原本就是1,所以改了原值并没有改
console.log(map1 === map2) //true ,所以这里是true

 get方法

首先来看下js对象里面

const obj = {a: "one"}
console.log(obj["a"])//在用[]的时候里面要不是个字符串,就是一个变量,不能obj[a]获取,这样会报错a is a notdefind


//但是当key是一个数字的时候,我们可以
const obj = {1: "one"} 
console.log(obj[1],obj["1"]) //这样可以获取

在immutable对象中只能用['字符串'] 

例如

 const obj = {1: "one"}
const map1 = fromJS(obj) //将原生的js对象({},[])转化为immutable对象
console.log(map1.get(1),map1.get('1')) // undefined one  通过写数字是拿不到的

 对于深度的元素取值 和修改值 通过 getIn([deep1,deep2,....]) updateIn([deep1,deep2],修改的回调)

setIn   getIn   updateIn方法

例如:

const nested = fromJS({ a: { b: { c: [3, 4, 5] } } }); //这是一个深层嵌套的对象
//我们想改变深层的b的值,当我们用set的时候
const map1 = nested.set("b",123) 
 console.log(map1.toJS()) //这样打印出来是{ a: { b: { c: [Array] } }, b: 123 },set是找第一层,有的话就修改,没有的话就添加,第一层没b所以就添加了一个b:123

 setIn   改深层次的值,例如

 const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
const map1 = nested.setIn(["a", "b"],"hehehda")
 console.log(map1.toJS()) //{ a: { b: 'hehehda' } },这样就能修改深层次的b的value了

updateIn   通过 更新这个方法更新深层的值,可以操作之前的值,第二个参数是一个回调

const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
const map1 = nested.updateIn(['a','b'],(value) => {
  console.log('xxx',value.toJS()) 
//xxx { c: [ 3, 4, 5 ] },所以这里的value是b的value,所以我们下面可以return对这个value进行操作的值
  return 123 //return这个值就是代替b的value
})
 console.log(map1.toJS())

getIn     获取深层次的值 ,例如

const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
console.log(nested.getIn(["a", "b"]).toJS());
//{ c: [ 3, 4, 5 ] },会直接拿到对象b的值

equals方法

用处:判断immutable对象值是不是相等

例如:

const map1 = Map({
  a:1,
  b:2,
  c:3
})
const map2 = Map({
  a:1,
  b:2,
  c:3
})
console.log(map1 === map2) //false这两个里面的值是一样的,但是地址不一样是false
console.log(map1 == map2)//false  同样是false
console.log(map1.equals(map2))//equals是用来判断值是否相等的,这两个的值相等,所以返回true

之前我们在判断两个对象的值是否相等的时候是使用JSON.stringify()转换成Json字符串在进行比较。例如

const obj1 = {
  a:1,
  b:2,
  c:3
}
const obj2 = {
  a:1,
  b:2,
  c:3
}
console.log(obj1 === obj2) // false
console.log(obj1 == obj2) // fasle
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)) // true

map方法 

之前是用在数组的现在用来处理对象,例如

const map1 = Map({ a: 1, b: 2, c: 3 });
const result = map1.map((v,k) => { //对对象进行了映射,改变为其他值在返回出来
  console.log(v,k) //1 a 2 b 3 c
  return v*v
})
console.log(result.toJS()) //{ a: 1, b: 4, c: 9 }

json方法 

之前是把数组拼接起来,这里是对对象的value的值进行拼接,例如

const map1 = Map({ a: 1, b: 2, c: 3 });
 console.log(map1.join("**"))//输出来的是1**2**3

merge方法

 通过merge 可以合并map对象与原生js对象 并且前面的map会被obj覆盖,如果map在后面不会覆盖obj里的属性,例如

const map1 = Map({ a: 1, b: 2, c: 3 });
const obj = { o:100, a:200, d:111 } //obj里面的a覆盖了Map1里面的a,但是map2里面的d不会覆盖obj里面的d
const map2 = Map({  b: 4, c: 6, d:5  });
const map3 = map1.merge(map2,obj)
console.log(map3.toJS()) //{ a: 200, b: 4, c: 6, d: 111, o: 100 }

List

是用来处理数组的

例如:

const list1 = List([1,2])
const list2 = list1.push(3,4,5) //不在返回的是长度而是,拼接成的新数组,并且不会改变原数组
const list3 = list1.unshift(0)//不在返回的是长度而是,拼接成的新数组,并且不会改变原数组
const list4 = list1.concat(list2,list3)
console.log(list1.toArray())//[1,2]
console.log(list2.toArray())[1,2,3,4,5]
console.log(list3.toArray())[0,1,2]
console.log(list4.toArray())//[1, 2, 1, 2, 3, 4, 5, 0, 1, 2]

concat方法

他会把List对象与数组拼接起来,当然同样其他方法,push,unshift也都可以例如

const list = List([1,2])
const result = list.concat(List([2,4]),[1,2,3])
console.log(result.toJS())//[1, 2, 2, 4,1, 2, 3]

Seq

惰性计算,用到的时候才处理不用的时候不计算

例如

const map1 = Map({
  a:1,
  b:2,
  c:3
})
const seq = Seq(map1).map((v,k) => {
  console.log(v,k)
  return v
} )

 console.log(seq.toJS())
//1 a 2 b 3 c  这是上面的console.log(v,k)
//{ a: 1, b: 2, c: 3 } //上面的return v

//这里要是没有使用的话,上面的console.log(v,k)是不会执行的

fromJS

将原生的js对象({},[])转化为immutable对象

例如:

const obj = {1: "one"}
const map1 = fromJS(obj)

//这里就相当于我们之前的
const map1 =Map({1: "one"})
//数组的话也是同样的
const array =[1,2]
const list1 =fromJS(array )
//就相当于我们之前的
const list1 = List([1,2])

Set

const map1 = Map({a:1,b:2,c:3})
const map2 = Map({a:1,b:2,c:3}) //随便改变一个值,下面就是false
const set = Set().add(map1)
console.log(set.has(map2)) //true

is

也是来判断两个immutable对象的值是不是一样

const map1 = Map({a:1,b:2,c:3})
const map2 = map1.set('b',1000)
const map3 = map1.set('b',1000)
console.log(map2 === map3) //false,因为是通过map1,返回出来了两个不同的对象,地址不一样

console.log(map2.equals(map3))//true
console.log(is(map2,map3))//true //两个的值都是一样的
console.log(is(map1, map2))//false//两个的值都是不一样的

在redux里面的reducer函数用的时候

方法一:只在函数里面用

思路:

在reducer的入口将将所有的state通过fromjs 处理成immutable对象,return 值得时候在将immutable变成js对象

1. 只在reducer中使用immutable 正常的组件中还是使用原生js对象,组件的代码不需要改动

2. formjs tojs 效率相对要低

代码:

const DefaultState = {
  info: {
    age: 16
  }
}
import {Map, fromJS} from "immutable" 
import { CHANGE_AGE, CHANGE_NAME } from "./actionTypes";
export default (prevState = DefaultState, action) => {
  // const newData =JSON.parse(JSON.stringify(prevState));
  console.log("prevState", prevState)
  let newData = null;
  let preImmutable = fromJS(prevState)
  // 注意不能修改源数据
  const { type, payload } = action;
  switch (type) {
    case CHANGE_NAME:
      newData.name = payload;
      break;
    case CHANGE_AGE: //点击实现改名的事件
      newData = preImmutable.setIn(["info","age"],30)
      console.log("xxxxnewData",newData)
      break;
    default:
      newData = preImmutable
      break;
  }

  return newData.toJS();
};

方法二:

​​​​​​​

  不论实在reducer 还是在组件中都使用immutable

  import {map} from "immutable"

  import { combineReducers } from "redux-immutable"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值