【immutable 学习记录】 immutable 中 list 的用法

发布于:2023-01-21 ⋅ 阅读:(511) ⋅ 点赞:(0)


什么是immutable

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

其中有 3 种最重要的数据结构:

  • Map:键值对集合,对应于 Object,ES6 也有专门的 Map 对象
  • List:有序可重复的列表,对应于 Array
  • Set:无序且不可重复的列表

本文介绍了 List 结构

List 的介绍及 API

List 对应原生 js的数组结构
创建List时需注意:list是工厂方法,不能使用new初始化

const {List} = require('immutable')
// const list = new List([1,2,3,4])  不能这么写
const list =  List([1,2,3,4])
console.log(list)


两个静态方法:List.isList() 和 List.of()*
```javascript
// List.isList()----判断是否是List类型
console.log("isList1:" , List.isList(list))
console.log("isList2:" , List.isList([1,2,3,4]))

// List.of()------创建新的List
const l =List.of(1,2,3,4,5)
console.log('l:', l)

// size 是取得list的长度
console.log("list的Size:" , list.size)
console.log("l的Size:" , l.size)

// set 方法用来设定指定下标的值 set(下标,值),支持下标为负数的设定

const l2 = List.of(1,2,3,4)
console.log("l2:", l2)
const l3 = l2.set(0,1111)
console.log("l3:", l3)

// 没有填充的地方默认是undefined
const l4 = l2.set(8, 666)
console.log("l4:", l4)

// 下标可以是负数
// -1 是指从右往左数查第 1 个
const l5 = l2.set(-1, 999)
console.log("l5:", l5)
const l5_1 = l2.set(-3, 999999)
console.log("l5_1:", l5_1)

// delete 删除指定下标的值 delete(下标),支持下标为负数的删除
const d1 = List([1,2,3,4,5])
console.log('d1:', d1)
const d2 = d1.delete(0)
console.log('d2:', d2)
const d3 = d1.delete(-2)
console.log('d3:', d3)

// insert 插入值 insert(下标,值),支持下标为负数的插入
const i1 = List([1,2,3,4])
console.log('i1:', i1)
const i2 = i1.insert(1, 666)
console.log('i2:', i2)
// 插入之后把整个数组往后移动一下,immutable实现的时候会把整个数组进行一次完整的拷贝

// update 用来更新指定下标的值(下标,callback),支持下标为负数的更新
const u1 = List([1,2,3,4])
console.log('u1:', u1)
const u2 = u1.update(1, x => x+100) // 把下标为 1 位置上的数据加100
console.log('u2:', u2)

// clear 用来清空并返回一个长度为0的新数组()
const c1 = List([1,2,3,4])
const c2 = c1.clear()
console.log('c1:', c1)
console.log('c2:', c2)

// push pop unshift shift 同原生数组的同名方法
/**
 * 1、push()、pop()和unshift()、shift()
  这两组同为对数组的操作,并且会改变数组的本身的长度及内容。
  不同的是 push()、pop() 是从数组的尾部进行增减,unshift()、shift() 是从数组的头部进行增减。
 var arr = [1, 2];

2、push()和unshift()
  向数组的 尾部/头部 添加若干元素,并返回 数组的 新长度;
  arr.push(3,4);         //返回 arr 的新长度 4
  arr ;                        // arr = [1,2,3,4];
  arr.unshift(0,0.5);    // 返回 arr 的新长度 6
  arr ;                       // arr = [0,0.5,1,2,3,4];

3、pop()和shift()
  从数组的 尾部/头部 删除1个元素(删且只删除1个),并返回 被删除的元素;空数组是继续删除,不报错,但返回undefined;
  arr.pop();      //返回 4;
  arr ;          // arr = [0,0.5,1,2,3];
  arr.pop();      //返回 3;
  arr ;         // arr = [0,0.5,1,2];
  arr.shift();      // 返回 0 ;
  arr ;        // arr = [0.5,1,2]

  PS: pop()和shift() 不接受传参,即使传了参数也没什么卵用~~;
  arr.pop(3) ;           // 返回 2;永远返回最后一个;
  arr ;        // arr = [0.5,1];
  arr.shift(1);    // 返回 0.5; 永远返回第一个;
  arr ;        // arr = [1];
  arr.pop() ;     // 返回 1;
  arr ;        // arr = [];
  arr.shift()     // 返回 undefined;
  arr ;        // arr = [];
 */

// setSize 重新设定数组长度,小于原数组长度会被截断,大于原数组长度会用undefined进行填充
const set1 = List([1,2,3,4,5,6]);
const set2 = set1.setSize(2);
console.log('set2:', set2);
const set3 = set1.setSize(9);
console.log('set3', set3)

// setIn() 对应嵌套型数组结构(二维数组),用来设定嵌套的值 ([第一层下标,第二次下标,....第N层下标],值)
// 同理还有 deleteIn,insertIn,updateIn
const arr1 = List([
    List([1,2,3,4]),
    List([11,22,33,44]),
    List([111,222,333,444]),
])

const arr2 = arr1.setIn([2,1],1000000)  //将 arr1 中第二行第一列 即 222 的位置变成 1000000
console.log("arr2:", arr2)

// concat 连接 List concat(List1, List2, ....ListN)---连接 N 个数组
const list1 = List([1,2,3,4,5])
const list2 = List([11,222])
const list3 = List([666,999])

const totalListc = list1.concat(list2,list3)
console.log('totalListc:', totalListc)

// merge 是 concat 的别名
const totalListm = list1.concat(list2,list3)
console.log('totalListm:', totalListm)

// map 同原生的map,循环并返回新的 List

// fliter 同原生的filter,循环过滤并返回新的 List

/**
 * filter()方法的使用
filter 它用于把Array的某些元素过滤掉,然后返回剩下的元素。

和map()类似,Array的filter()也接收一个函数;

和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

例如,在一个Array中,删掉偶数,只保留奇数,可以这么写
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
    return x % 2 !== 0;
});
r; // [1, 5, 9, 15]

把一个Array中的空字符串删掉,可以这么写:
var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
    return s && s.trim(); // 注意:IE9以下的版本没有trim()方法;trim()函数去掉字符串首尾空白字符
});
arr; // ['A', 'B', 'C']

回调函数

filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次打印'A', 'B', 'C'
    console.log(index); // 依次打印0, 1, 2
    console.log(self); // self就是变量arr
    return true;
});

利用filter,可以巧妙地去除Array的重复元素:
var r, arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
    r = arr.filter(function (element, index, self) {
    return self.indexOf(element) === index;
});
alert(r.toString());
indexOf总是返回第一个元素的位置,后续的重复元素位置与indexOf返回的位置不相等,因此被filter滤掉了,所以重复的元素仅会保留第一个位置的元素

map()方法
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果

例子1:
var array1 = [1,4,9,16];
const map1 = array1.map(x => x *2);
console.log(map1);	// Array [2,8,18,32]
例子2:
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => {
    if (x == 4) {
        return x * 2;
    }
});
console.log(map1);	//Array [undefined, 8, undefined, undefined]
为什么会出现三个undefined呢?而不是我预期的[1,8,9,16]。
这样写只是增加了一个条件,即x的值为4时才乘以2,之所以会出现undefined,是因为map()方法创建了一个新数组,但新数组并不是在遍历完array1后才被赋值的,而是每遍历一次就得到一个值。所以,下面这样修改后就正确了:
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => {
    if (x == 4) {
        return x * 2;
    }
    return x;	//Array [1,8,9,16]
});
这里注意箭头函数有两种格式:
1.只包含一个表达式,这时花括号和return都省略了。
2.包含多条语句,这时花括号和return都不能省略。 
 * 
 */

// flatten 扁平化这个list

const fl1 = List([
    List([1,2,3,4]),
    List([11,22,33,44]),
    List([111,222,333,444]),
]);
const fl2 = fl1.flatten(true);  // true 代表浅拉平,只拉平第一层;   false 代表深拉平,拉平N层;    写数值代表拉平到第几层
console.log('fl2', fl2)

// find 查找,返回第一个符合的结果
const name = List(['张三','张四', '张五', '李四', '王五', '张晓晓']);
const names = name.find((v,k, name) => v.indexOf('张') !== -1)  //字符串的查找方法
console.log('names:',names)

// findLast 查找,返回最后一个符合的结果
const namel = List(['张三','张四', '张五', '李四', '王五', '张晓晓']);
const namesl = namel.findLast((v,k, namel) => v.indexOf('张') !== -1)  //字符串的查找方法
console.log('namels:',namesl)

// keys 返回所有的下标
const keys = name.keys()
console.log('keys:', keys)
for(const k of keys){
    console.log('keys:', k)
}

// values 返回所有的值
const values = name.values()
console.log('values:', values)
for(const v of values){
    console.log('values:', v)
}

// entries 返回所有entry,(key, value) 形式
const entries = name.entries()
console.log('entries:', entries)
for(const e of entries){
    console.log('entries:', e)
}

// groupBy 分组
const people = List([
    {sex: 'male', name:'Nick'},
    {sex: 'female', name:'Susan'},
    {sex: 'male', name:'Mike'},
    {sex: 'female', name:'Nancy'},
])
const gB = people.groupBy(x => x.sex)
console.log('groupBy:', gB)

/**
 * 总结:
 * 1. 这个数据结构拥有数组的大多数属性方法,和数组基本兼容
 * 2. 取值 get ,  赋值set,  循环 .forEach(),  循环并返回一个新的数组 .Map(),  过滤  filter
 */


网站公告

今日签到

点亮在社区的每一天
去签到

热门文章