remeda.js中文文档 前端工具库,类似于ts版的lodash.js+ramda.js

1,377 阅读30分钟

remeda中文文档

[TOC]

一.简介

  • 出现原因:没有好的实用程序库可以很好地与 TypeScript 配合使用。使用 Lodash 或 Ramda 时,有时必须手动注释类型。Remeda 是用 TypeScript 编写和测试的, 意味着用户不需要自定义类型。如果是ts应用,优先推荐该库
  • 当前版本:v1.2.0
  • 英文官网api文档全部整理翻译过来的,如遇问题,可联系译者邮箱:1311140141@qq.com

二.说明

  • remeda的方法均不会改变传入的数据,只会返回新的数据。(不会产生副作用)
  • 如下所示,大多数的remeda方法都有两种用法,数据在前和数据在后。后面文档参数部分均按数据在前的方式写。数据在后的方式自己推断
R.pick(obj, ['firstName', 'lastName']); // 数据在前  推荐
R.pipe(obj, R.pick(['firstName', 'lastName'])); // 数据在后

R.pick(['firstName', 'lastName'], obj); // 错误用法,无法工作
R.pick(['firstName', 'lastName'])(obj); // 这是数据在后,可以工作,但类型无法推断
  • 当使用pipe方法时,许多方法都支持惰性求值。文档中会以 [p] 标识。
// Get first 3 unique values
const arr = [1, 2, 2, 3, 3, 4, 5, 6];

const result = R.pipe(
  arr,                    // only four iterations instead of eight (array.length)
  R.map(x => {
    console.log('iterate', x);
    return x;
  }),
  R.unique(),
  R.take(3)
); // => [1, 2, 3]

/**
 * Console output:
 * iterate 1
 * iterate 2
 * iterate 2
 * iterate 3
 * /
  • 可迭代函数都有一个额外的indexed属性, 和(element, index, array)的许多方法相似. 文档中以 [i] 标识
const arr = [10, 12, 13, 3];

// filter even values
R.filter(arr, x => x % 2 === 0); // => [10, 12]

// filter even indexes
R.filter.indexed(arr, (x, i, array) => i % 2 === 0); // => [10, 13]

方法名简介

描述

用法:

  • 数据在前用法
  • 数据在后用法

参数:

  • 参数名 (参数类型): 参数描述

返回:

(返回类型): 返回描述

例子:

// 实例代码

三.Number

[clamp限制值范围]

将给定值限制在最小和最大范围内。

用法:

  • R.clamp(value, { [min], [max] })
  • R.clamp({ [min], [max] })(value)

参数:

  • value (Number): 需要限制的对象
  • [min] (Number): 限制的最小值
  • [max] (Number): 限制的最大值

返回:

(Number): 返回经过限制处理后的值

例子:

clamp(10, { min: 20 }) // => 20
clamp(10, { max: 5 }) // => 5
clamp(10, { max: 20, min: 5 }) // => 10

clamp({ min: 20 })(10) // => 20
clamp({ max: 5 })(10) // => 5
clamp({ max: 20, min: 5 })(10) // => 10

[add两值相加]

用法:

  • R.add(value, addend);
  • R.add(addend)(value);

例子:

R.add(10, 5); // => 15
R.add(10, -5); // => 5
R.reduce([1, 2, 3, 4], R.add, 0); // => 10

R.add(5)(10); // => 15
R.add(-5)(10); // => 5
R.map([1, 2, 3, 4], R.add(1)); // => [2, 3, 4, 5]

[subtract两值相减]

用法:

  • R.subtract(value, subtrahend);
  • R.subtract(subtrahend)(value);

例子:

R.subtract(10, 5); // => 5
R.subtract(10, -5); // => 15
R.reduce([1, 2, 3, 4], R.subtract, 20); // => 10

R.subtract(5)(10); // => 5
R.subtract(-5)(10); // => 15
R.map([1, 2, 3, 4], R.subtract(1)); // => [0, 1, 2, 3]

[multiply两值相乘]

用法:

  • R.multiply(value, multiplicand);
  • R.multiply(multiplicand)(value);

例子:

R.multiply(3, 4); // => 12
R.reduce([1, 2, 3, 4], R.multiply, 1); // => 24

R.multiply(4)(3); // => 12
R.map([1, 2, 3, 4], R.multiply(2)); // => [2, 4, 6, 8]

[divide两值相除]

用法:

  • R.divide(value, divisor);
  • R.divide(divisor)(value);

例子:

R.divide(12, 3); // => 4
R.reduce([1, 2, 3, 4], R.divide, 24); // => 1

R.divide(3)(12); // => 4
R.map([2, 4, 6, 8], R.divide(2)); // => [1, 2, 3, 4]

[sumnumber数组累加]

空数组返回0

用法:

  • R.sum(data);
  • R.sum()(data);

例子:

R.sum([1, 2, 3]); // => 6
R.sum([]); // => 0

R.pipe([1, 2, 3], R.sum()); // => 6
R.pipe([], R.sum()); // => 0

[productnumber数组累乘]

空数组返回0

用法:

  • R.product(data);
  • R.product()(data);

例子:

R.product([1, 2, 3]); // => 6
R.product([]); // => 0

R.pipe([1, 2, 3], R.product()); // => 6
R.pipe([], R.product()); // => 0

[ceil向上取整到指定的小数位]

可以给负值

用法:

  • R.ceil(value, precision);
  • R.ceil(precision)(value);

例子:

R.ceil(123.9876, 3); // => 123.988
R.ceil(483.22243, 1); // => 483.3
R.ceil(8541, -1); // => 8550
R.ceil(456789, -3); // => 457000

R.ceil(3)(123.9876); // => 123.988
R.ceil(1)(483.22243); // => 483.3
R.ceil(-1)(8541); // => 8550
R.ceil(-3)(456789); // => 457000

[floor向下取整到指定的小数位]

可以给负值

用法:

  • R.floor(value, precision);
  • R.floor(precision)(value);

例子:

R.floor(123.9876, 3); // => 123.987
R.floor(483.22243, 1); // => 483.2
R.floor(8541, -1); // => 8540
R.floor(456789, -3); // => 456000

R.floor(3)(123.9876); // => 123.987
R.floor(1)(483.22243); // => 483.2
R.floor(-1)(8541); // => 8540
R.floor(-3)(456789); // => 456000

[round四舍五入到指定的小数位]

可以给负值

用法:

  • R.round(value, precision);
  • R.round(precision)(value);

例子:

R.round(123.9876, 3); // => 123.988
R.round(483.22243, 1); // => 483.2
R.round(8541, -1); // => 8540
R.round(456789, -3); // => 457000

R.round(3)(123.9876); // => 123.988
R.round(1)(483.22243); // => 483.2
R.round(-1)(8541); // => 8540
R.round(-3)(456789); // => 457000

四.String

[randomString获取随机字符串]

从a-zA-Z0-9中生成一个固定长度的随机字符串

用法:

  • randomString(length)

例子:

randomString(5) // => aB92J

[sliceString截取字符串]

String.prototype.slice 的数据在后版本

用法:

  • R.sliceString(indexStart)(string); / R.sliceString(indexStart, indexEnd)(string);

例子:

R.sliceString(1)(`abcdefghijkl`); // => `bcdefghijkl`
R.sliceString(4, 7)(`abcdefghijkl`); // => `efg`

五.Object

[addProp给对象新增属性]

用法:

  • R.addProp(obj, prop, value)
  • R.addProp(prop, value)(obj)

参数:

  • obj (Object) 目标对象
  • prop (String) 要添加的key名称
  • value (any) 要添加的key对应的值

返回:

(Object): 返回新的对象

例子:

R.addProp({ firstName: 'john' }, 'lastName', 'doe') // => {firstName: 'john', lastName: 'doe'}

R.addProp('lastName', 'doe')({ firstName: 'john' }) // => {firstName: 'john', lastName: 'doe'}

[omit删除指定键]

返回原对象删除指定键后的新对象

用法:

  • R.omit(obj, names)
  • R.omit(names)(obj)

例子:

R.omit({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'd']) // => { b: 2, c: 3 }

R.pipe({ a: 1, b: 2, c: 3, d: 4 }, R.omit(['a', 'd'])) // => { b: 2, c: 3 }

[omitBy删除指定键]

返回原对象删除指定键(匹配断言)后的新对象

用法:

  • R.omitBy(object, fn)
  • R.omitBy(fn)(object)

例子:

R.omitBy({ a: 1, b: 2, A: 3, B: 4 }, (val, key) => key.toUpperCase() === key) // => {a: 1, b: 2}

R.omitBy((val, key) => key.toUpperCase() === key)({ a: 1, b: 2, A: 3, B: 4 }) // => {a: 1, b: 2}

[set设置对象属性值]

设置对象属性的值

用法:

  • R.set(obj, prop, value)
  • R.set(prop, value)(obj)

例子:

R.set({ a: 1 }, 'a', 2) // => { a: 2 }

R.pipe({ a: 1 }, R.set('a', 2)) // => { a: 2 }

[setPath设置对象属性值]

设置对象属性的值

用法:

  • R.setPath(obj, path, value);
  • R.setPath(path, value)(obj);

例子:

R.setPath({ a: { b: 1 } }, ["a", "b"], 2); // => { a: { b: 2 } }

R.pipe({ a: { b: 1 } }, R.setPath(["a", "b"], 2)); // { a: { b: 2 } }

注: 上面的方法是不会对原对象修改,而是返回一个新的对象,可以自己封装一个修改原对象的方法

/**
 * @description: 设置对象深度路径的值,直接在原对象上修改
 */
export function ObjSetPathCur<T>(obj: T, path: any[], value: any): void {
  let currentObj: any = obj;

  for(let i=0; i<path.length; i++) {
    if(i < path.length-1) {
      if(!currentObj[path[i]]) currentObj[path[i]] = {};

      currentObj = currentObj[path[i]]
    }else {
      currentObj[path[i]] = value;
    }
  }
}

[prop获取对象属性值]

获取属性对应的值

用法:

  • R.prop(prop)(object)

例子:

R.pipe({ foo: 'bar' }, R.prop('foo')) // => 'bar'

[pathOr根据路径获取值]

根据路径获取值,如果值返回(undefined\null), 则返回默认值

用法:

  • R.pathOr(object, array, defaultValue)
  • R.pathOr(array, defaultValue)(object)

例子:

R.pathOr({ x: 10 }, ['y'], 2) // 2
R.pathOr({ y: 10 }, ['y'], 2) // 10
R.pathOr({ x: 10, y: {name: 'ww'} }, ['y', 'name'], 'ss') // ww

R.pipe({ x: 10 }, R.pathOr(['y'], 2)) // 2

[pick摘取对象的部分属性生成新对象]

摘取对象的部分属性生成新对象

用法:

  • R.pick(object, [prop1, prop2])
  • R.pick([prop1, prop2])(object)

例子:

R.pick({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'd']) // => { a: 1, d: 4 }

R.pipe({ a: 1, b: 2, c: 3, d: 4 }, R.pick(['a', 'd'])) // => { a: 1, d: 4 }

[pickBy摘取对象的部分属性生成新对象]

摘取对象的部分属性(根据断言摘取)生成新对象

用法:

  • R.pickBy(object, fn)
  • R.pickBy(fn)(object)

例子:

R.pickBy({ a: 1, b: 2, A: 3, B: 4 }, (val, key) => key.toUpperCase() === key) // => {A: 3, B: 4}

R.pickBy((val, key) => key.toUpperCase() === key)({ a: 1, b: 2, A: 3, B: 4 }) // => {A: 3, B: 4}

[clone深复制]

深复制值,支持类型:Array, Object, Number, String, Boolean, Date, RegExp

用法:

  • R.clone(value)

参数:

  • value (Object): 要深复制的目标对象

返回:

(Object): 返回新的目标对象

例子:

R.clone({ foo: 'bar' }) // {foo: 'bar'}

[keys获取对象属性集合][p][strict]

返回包含对象或数组所有key的集合

用法:

  • R.keys(source) \ R.keys.strict(source)

例子:

R.keys(['x', 'y', 'z']) // => ['1', '2', '3'], typed Array<string>
R.keys({ a: 'x', b: 'y', c: 'z' }) // => ['a', 'b', 'c'], typed Array<string>
R.pipe({ a: 'x', b: 'y', c: 'z' }, R.keys, R.first) // => 'a',
R.keys.strict({ a: 'x', b: 'y', c: 'z' } as const) // => ['a', 'b', 'c'], typed Array<'a' | 'b' | 'c'>

[values获取对象属性值集合][p]

返回包含对象或数组所有value的集合

用法:

  • R.values(source)

例子:

R.values(['x', 'y', 'z']) // => ['x', 'y', 'z']
R.values({ a: 'x', b: 'y', c: 'z' }) // => ['x', 'y', 'z']
R.pipe({ a: 'x', b: 'y', c: 'z' }, R.values, R.first) // => 'x'

[entries获取对象key/value集合][strict]

返回包含对象或数组所有key/value的集合

用法:

  • R.entries(object); / R.entries.strict(object);
  • R.entries()(object); / R.entries.strict()(object);

例子:

R.entries({ a: 1, b: 2, c: 3 }); // => [['a', 1], ['b', 2], ['c', 3]]
R.entries.strict({ a: 1 } as const); // => [['a', 1]] typed Array<['a', 1]>

R.pipe({ a: 1, b: 2, c: 3 }, entries()); // => [['a', 1], ['b', 2], ['c', 3]]
R.pipe({ a: 1 } as const, entries.strict()); // => [['a', 1]] typed Array<['a', 1]>

[forEachObj遍历对象]

使用定义的回调函数遍历对象,最后返回原对象

用法:

  • R.forEachObj(object, fn)
  • forEachObj(fn)(object)

例子:

R.forEachObj({ a: 1 }, (val) => {
  console.log(`${val}`)
}) // "1"
R.forEachObj.indexed({ a: 1 }, (val, key, obj) => {
  console.log(`${key}: ${val}`)
}) // "a: 1"

R.pipe(
  { a: 1 },
  R.forEachObj((val) => console.log(`${val}`))
) // "1"

[merge对象合并]

  • 两个对象合并,类似Object.assign
  • b对象会覆盖a对象中所有的相同属性

用法:

  • R.merge(a, b)
  • R.merge(b)(a)

例子:

R.merge({ x: 1, y: 2 }, { y: 10, z: 2 }) // => { x: 1, y: 10, z: 2 }

R.merge({ y: 10, z: 2 })({ x: 1, y: 2 }) // => { x: 1, y: 10, z: 2 }

R.mergeDeep({
  id: 1,
  name: 'zz',
  obj: {
    key1: 1
  }
}, {
  name: 'ss',
  obj: {
    key2: 2
  }
}) 
//  结果如下
{
    "id": 1,
    "name": "ss",
    "obj": { // 只合并到第一层
        "key2": 2
    }
}

[mergeDeep对象深度合并]

  • 两个对象合并,如果某个Key的值是对象。则继续对该子对象进行内部遍历合并

用法:

  • R.mergeDeep(destination, source);
  • R.mergeDeep(source)(destination);

例子:

R.mergeDeep({ foo: "bar", x: 1 }, { foo: "baz", y: 2 }); // => { foo: 'baz', x: 1, y: 2 }

R.pipe({ foo: "bar", x: 1 }, R.mergeDeep({ foo: "baz", y: 2 })); // => { foo: 'baz', x: 1, y: 2 }

R.mergeDeep({
  id: 1,
  name: 'zz',
  obj: {
    key1: 1
  }
}, {
  name: 'ss',
  obj: {
    key2: 2
  }
}) 
//  结果如下
{
    "id": 1,
    "name": "ss",
    "obj": { // 深合并
        "key1": 1,
        "key2": 2
    }
}

[mergeAll多对象合并]

把一个对象数组合并为一个单对象

用法:

  • R.mergeAll(objects)

例子:

R.mergeAll([{ a: 1, b: 1 }, { b: 2, c: 3 }, { d: 10 }]) // => { a: 1, b: 2, c: 3, d: 10 }

[hasSubObject对象B是否是对象A的子对象]

如果对象B的每一个属性和对应的值 在 对象A中的存在(key和value都相等),则认为B是A的子对象(主要A允许拥有B所没有的key) 内部使用isDeepEqual方法

用法:

  • R.hasSubObject(data, subObject);
  • R.hasSubObject(subObject)(data);

例子:

R.hasSubObject({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 }); //=> true
R.hasSubObject({ a: 1, b: 2, c: 3 }, { b: 4 }); //=> false
R.hasSubObject({ a: 1, b: 2, c: 3 }, {}); //=> true

R.hasSubObject({ a: 1, c: 3 })({ a: 1, b: 2, c: 3 }); //=> true
R.hasSubObject({ b: 4 })({ a: 1, b: 2, c: 3 }); //=> false
R.hasSubObject({})({ a: 1, b: 2, c: 3 }); 

----------分割线------------

[mapKeys映射生成新的key]

映射生成新的key, 但原value保持不变

用法:

  • R.mapKeys(object, fn)
  • R.mapKeys(fn)(object)

例子:

R.mapKeys({ a: 1, b: 2 }, (key, value) => key + value) // => { a1: 1, b2: 2 }

R.pipe(
  { a: 1, b: 2 },
  R.mapKeys((key, value) => key + value)
) // => { a1: 1, b2: 2 }

[mapValues映射生成新的value]

映射生成新的value, 但原key保持不变

用法:

  • R.mapValues(object, fn)
  • R.mapValues(fn)(object)

例子:

R.mapValues({ a: 1, b: 2 }, (value, key) => value + key) // => {a: '1a', b: '2b'}

R.pipe(
  { a: 1, b: 2 },
  R.mapValues((value, key) => value + key)
) // => {a: '1a', b: '2b'}

[objOf创建只包含一对key: value的对象]

创建只包含一对key: value的对象

用法:

  • R.objOf(value, key)

例子:

R.objOf(10, 'a') // => { a: 10 }

R.pipe(10, R.objOf('a')) // => { a: 10 }

[evolve给对象的每一个key定义一个处理函数]

通过将evolver对象参数中包含的函数根据其对应的路径应用于data对象参数来创建新对象。 如果data对象中不存在evolver对象对应的键,则不会调用evolver中包含的函数。此外,如果evolver对象中不存在data对象的对应键,则data对象中包含的值将保持原样。

  • 和toPairs相反

用法:

  • R.evolve(data, evolver);
  • R.evolve(evolver)(data);

例子:

const evolver = {
  count: add(1),
  time: { elapsed: add(1), remaining: add(-1) },
};
const data = {
  id: 10,
  count: 10,
  time: { elapsed: 100, remaining: 1400 },
};
evolve(data, evolver);
// => {
//   id: 10,
//   count: 11,
//   time: { elapsed: 101, remaining: 1399 },
// }

const evolver = {
  count: add(1),
  time: { elapsed: add(1), remaining: add(-1) },
};
const data = {
  id: 10,
  count: 10,
  time: { elapsed: 100, remaining: 1400 },
};
R.pipe(object, R.evolve(evolver));
// => {
//   id: 10,
//   count: 11,
//   time: { elapsed: 101, remaining: 1399 },
// }

六.Array

数组函数分类

  • 元素遍历:forEach \ map \ mapToObj \ indexBy \ flat \ flatMap \ mapWithFeedback
  • 元素统计: sumBy \ reduce \ meanBy
  • 元素筛选:first \ firstBy \ nthBy \ last \ take \ takeFirstBy \ takeWhile \ takeLastWhile \ find \ findIndex \ findLast \ findLastIndex \ filter \ intersection \ sample \ shuffle
  • 元素剔除: difference \ differenceWith \ drop \ dropFirstBy \ dropWhile \ dropLast \ dropLastWhile \ unique \ uniqueBy \ uniqWith
  • 数组拼接:concat \ zip \ zipWith
  • 数组拆分:chunk \ groupBy \ partition \ splitAt \ splitWhen
  • 其他:reverse \ sort \ sortBy \ flat \ flattenDeep \ range \ join \ swapIndices \ intersectionWith \ isIncludedIn

[forEach遍历数组][i][p]

用定义的回调函数遍历数组,最后返回原数组

用法:

  • R.forEach(array, fn) / R.forEach.indexed(array, fn)
  • R.forEach(fn)(array)

例子:

R.forEach([1, 2, 3], (x) => {
  console.log(x)
}) // => [1, 2, 3]
R.forEach.indexed([1, 2, 3], (x, i) => {
  console.log(x, i)
}) // => [1, 2, 3]

R.pipe(
  [1, 2, 3],
  R.forEach((x) => {
    console.log(x)
  })
) // => [1, 2, 3]

[map映射生成新数组][i][p]

根据定义的回调函数映射生成新数组

用法:

  • R.map(array, fn) / R.map.indexed(array, fn)
  • R.map(fn)(array)

例子:

R.map([1, 2, 3], (x) => x * 2) // => [2, 4, 6]
R.map.indexed([0, 0, 0], (x, i) => i) // => [0, 1, 2]

R.pipe(
  [0, 1, 2],
  R.map((x) => x * 2)
) // => [0, 2, 4]

[mapToObj映射生成新对象]

根据定义的回调函数映射生成新对象

用法:

  • R.mapToObj(array, fn) \ R.mapToObj.indexed(array, fn)
  • R.mapToObj(fn)(array)

例子:

R.mapToObj([1, 2, 3], (x) => [String(x), x * 2]) // => {1: 2, 2: 4, 3: 6}
R.mapToObj.indexed([0, 0, 0], (x, i) => [i, i]) // => {0: 0, 1: 1, 2: 2}

type DeviceType = '101' | '102' | '103';
type DeviceModelType = {id: DeviceType, name: string};
const models: Array<DeviceModelType> = [
  {id: '101', name: '门站'}, 
  {id: '102', name: '阀门'}, 
  {id: '103', name: '用户'}
]

const obj2 = R.mapToObj(models, item => [item.id, item]) // type: Record<DeviceType, DeviceModelType>

R.pipe(
  [1, 2, 3],
  R.mapToObj((x) => [String(x), x * 2])
) // => {1: 2, 2: 4, 3: 6}

[indexBy数组转对象][i]

通过fn返回的值做为key, 把数组转为对象

用法:

  • R.indexBy(array, fn)
  • R.indexBy(fn)(array)

例子:

R.indexBy(['one', 'two', 'three'], (x) => x.length) // => {3: 'two', 5: 'three'}

const arr = [{id: 1, name: 'a1'}, {id: 2, name: 'a2'}, {id: 3, name: 'a3'}]
const arrObj = R.indexBy(arr, item => item.id)
// {
//     "1": {
//         "id": 1,
//         "name": "a1"
//     },
//     "2": {
//         "id": 2,
//         "name": "a2"
//     },
//     "3": {
//         "id": 3,
//         "name": "a3"
//     }
// }

R.pipe(
  ['one', 'two', 'three'],
  R.indexBy((x) => x.length)
) // => {3: 'two', 5: 'three'}

补充:

  • 该函数返回对象的key固定是string; 有时希望Key的类型更具体。则用 mapToObj

[mapWithFeedback映射新数组-递归统计][i]

映射函数的第一个参数是上一次计算的结果或初始值。第二个参数是当前数组项。函数返回的结果作为下一次调用的第一个参数。

用法:

  • R.mapWithFeedback(items, fn, initialValue) / R.mapWithFeedback.indexed(items, fn, initialValue)
  • R.mapWithFeedback(fn, initialValue)(array)

例子:

R.mapWithFeedback([1, 2, 3, 4, 5], (prev, x) => prev + x, 100); // => [101, 103, 106, 110, 115]
R.mapWithFeedback.indexed(
  [1, 2, 3, 4, 5],
  (prev, x, i, array) => prev + x,
  100,
); // => [101, 103, 106, 110, 115]

R.pipe(
  [1, 2, 3, 4, 5],
  R.mapWithFeedback((prev, x) => prev + x, 100),
); // => [101, 103, 106, 110, 115]
R.pipe(
  [1, 2, 3, 4, 5],
  R.mapWithFeedback.indexed((prev, x, i, array) => prev + x, 100),
); // => [101, 103, 106, 110, 115]

[sumBy数组求和][i]

把回调函数返回的值全部加起来返回

用法:

  • R.sumBy(array, fn) / R.sumBy.indexed(array, fn)
  • R.sumBy(fn)(array)

例子:

R.sumBy([{ a: 5 }, { a: 1 }, { a: 3 }], (x) => x.a) // 9

R.pipe(
  [{ a: 5 }, { a: 1 }, { a: 3 }],
  R.sumBy((x) => x.a)
) // 9

[reduce数组累积计算][i]

类似js元素reduce, 数组的每个元素都会调用一次指定的回调函数fn. 上一个fn返回的结果,作为下一个fn的一个参数使用。

用法:

  • R.reduce(items, fn, initialValue)
  • R.reduce.indexed(items, fn, initialValue)

参数:

  • items (any): 数组元素
  • fn (Function): 指定的回调函数 函数接收四个参数acc//上一个回调函数的返回值, x//当前数组元素, i//当前元素索引, array//原数组
  • initialValue (any): 初始值,作为第一个回调函数的acc值

例子:

R.reduce([1, 2, 3, 4, 5], (acc, x) => acc + x, 100) // => 115

R.reduce.indexed([1, 2, 3, 4, 5], (acc, x, i, array) => acc + x, 100) // => 115

[meanBy数组平均值][i]

返回数组使用断言函数后的平均值

用法:

  • R.meanBy(array, fn) \ R.meanBy.indexed(array, fn);
  • R.meanBy(fn)(array) \ R.meanBy.indexed(fn)(array)

例子:

R.meanBy([{ a: 5 }, { a: 1 }, { a: 3 }], (x) => x.a); // 3

R.pipe(
  [{ a: 5 }, { a: 1 }, { a: 3 }],
  R.meanBy((x) => x.a),
); // 3

[first获取第一个元素][p]

获取数组第一个元素

用法:

  • R.first(array)
  • R.first()(array);

例子:

R.first([1, 2, 3]) // => 1
R.first([]) // => undefined

R.pipe(
  [1, 2, 4, 8, 16],
  R.filter((x) => x > 3),
  R.first(),
  (x) => x + 1
) // => 5

[firstBy自定义排序获取第一个元素][p]

获取数组中第一个符合所提供顺序规则的元素

用法:

  • R.firstBy(data, ...rules);
  • R.firstBy(...rules)(data);

例子:

const max = R.firstBy([1, 2, 3], [R.identity, "desc"]); // => 3;
const min = R.firstBy([1, 2, 3], R.identity); // => 1;

const data = [{ a: "a" }, { a: "aa" }, { a: "aaa" }] as const;
const maxBy = R.firstBy(data, [(item) => item.a.length, "desc"]); // => { a: "aaa" };
const minBy = R.firstBy(data, (item) => item.a.length); // => { a: "a" };

const data = [
  { type: "cat", size: 1 },
  { type: "cat", size: 2 },
  { type: "dog", size: 3 },
] as const;
const multi = R.firstBy(data, R.prop("type"), [R.prop("size"), "desc"]); // => {type: "cat", size: 2}

--------

const maxBy = R.pipe(data, R.firstBy([(item) => item.a.length, "desc"])); // => { a: "aaa" };
const minBy = R.pipe(
  data,
  R.firstBy((item) => item.a.length),
); // => { a: "a" };

const data = [
  { type: "cat", size: 1 },
  { type: "cat", size: 2 },
  { type: "dog", size: 3 },
] as const;
const multi = R.pipe(data, R.firstBy(R.prop("type"), [R.prop("size"), "desc"])); // => {type: "cat", size: 2}

[nthBy自定义排序获取第n个元素]

获取数组中第n个符合所提供顺序规则的元素

用法:

  • R.nthBy(data, index, ...rules);
  • R.nthBy(index, ...rules)(data);

例子:

R.nthBy([2, 1, 4, 5, 3], 2, identity); // => 3

R.pipe([2, 1, 4, 5, 3], R.nthBy(2, identity)); // => 3

[last获取最后一个元素][p]

获取数组最后一个元素

注意: 在pipe函数中,使用last() 代替last; 因为last会丢失类型推断

用法:

  • R.last(array)

例子:

R.last([1, 2, 3]) // => 3
R.last([]) // => undefined
R.pipe(
  [1, 2, 4, 8, 16],
  R.filter((x) => x > 3),
  R.last(),
  (x) => x + 1
) // => 17

[take获取前n个元素][p]

从数组中返回前n个元素组成的新数组(数组内的元素如果是对象的话,只是浅引用,而不会深复制)

用法:

  • R.take(array, n)
  • R.take(n)(array)

例子:

R.take([1, 2, 3, 4, 3, 2, 1], 3) // => [1, 2, 3]

R.pipe([1, 2, 3, 4, 3, 2, 1], R.take(3)) // => [1, 2, 3]

[takeFirstBy获取前n个元素][p]

根据提供的排序条件从数组中返回前n个元素组成的新数组(数组内的元素如果是对象的话,只是浅引用,而不会深复制)

用法:

  • R.takeFirstBy(data, n, ...rules)
  • R.takeFirstBy(n, ...rules)(data)

例子:

R.takeFirstBy(["aa", "aaaa", "a", "aaa"], 2, (x) => x.length); // => ['a', 'aa']

R.pipe(
  ["aa", "aaaa", "a", "aaa"],
  R.takeFirstBy(2, (x) => x.length),
); // => ['a', 'aa']

[takeWhile获取前n个元素]

从数组中返回前n(n为断言第一次返回false处的索引)个元素组成的新数组(数组内的元素如果是对象的话,只是浅引用,而不会深复制)

用法:

  • R.takeWhile(array, fn)
  • R.takeWhile(fn)(array)

例子:

R.takeWhile([1, 2, 3, 4, 3, 2, 1], (x) => x !== 4) // => [1, 2, 3]

R.pipe(
  [1, 2, 3, 4, 3, 2, 1],
  R.takeWhile((x) => x !== 4)
) // => [1, 2, 3]

[takeLastWhile 获取后n个元素]

语法同上

[find筛选一个元素][i][p]

返回数组中第一个符合断言的元素,如果都没有,返回undefined

用法:

  • R.find(items, fn) \ R.find.indexed(items, fn)
  • R.find(fn)(items)

例子:

R.find([1, 3, 4, 6], (n) => n % 2 === 0) // => 4
R.find.indexed([1, 3, 4, 6], (n, i) => i>10) // undefined

R.pipe(
  [1, 3, 4, 6],
  R.find((n) => n % 2 === 0)
) // => 4

[findIndex筛选一个元素][i][p]

返回数组中第一个符合断言的元素的索引,如果都没有,返回-1

用法:

  • R.findIndex(items, fn) \ R.findIndex.indexed(items, fn)
  • R.findIndex(fn)(items)

例子:

R.findIndex([1, 3, 4, 6], (n) => n % 2 === 0) // => 2
R.findIndex.indexed([1, 3, 4, 6], (n, i) => i>10) // -1

R.pipe(
  [1, 3, 4, 6],
  R.findIndex((n) => n % 2 === 0)
) // => 2

[findLast从后开始筛选一个元素][i][p]

从数组的后面开始,返回第一个符合断言的元素,如果都没有,返回undefined

用法:

  • R.findLast(items, fn) \ R.findLast.indexed(items, fn)
  • R.findLast(fn)(items) \ R.findLast.indexed(fn)(items)

例子:

R.findLast([1, 3, 4, 6], (n) => n % 2 === 1); // => 3
R.findLast.indexed([1, 3, 4, 6], (n, i) => n % 2 === 1); // => 3

---------

R.pipe(
  [1, 3, 4, 6],
  R.findLast((n) => n % 2 === 1),
); // => 3
R.pipe(
  [1, 3, 4, 6],
  R.findLast.indexed((n, i) => n % 2 === 1),
); // => 3

[findLastIndex从后开始筛选一个元素][i][p]

从数组的后面开始,返回第一个符合断言的元素的索引,如果都没有,返回-1

用法:

  • R.findLastIndex(items, fn) \ R.findLastIndex.indexed(items, fn)
  • R.findLastIndex(fn)(items) \ R.findLastIndex.indexed(fn)(items)

例子:

R.findLastIndex([1, 3, 4, 6], (n) => n % 2 === 1); // => 1
R.findLastIndex.indexed([1, 3, 4, 6], (n, i) => n % 2 === 1); // => 1

R.pipe(
  [1, 3, 4, 6],
  R.findLastIndex((n) => n % 2 === 1),
); // => 1
R.pipe(
  [1, 3, 4, 6],
  R.findLastIndex.indexed((n, i) => n % 2 === 1),
); // => 1

[filter筛选多个元素][i][p]

在数组中筛选符合回调函数中的条件的元素

用法:

  • R.filter(array, fn) \ R.filter.indexed(array, fn)
  • R.filter(fn)(array)

例子:

R.filter([1, 2, 3], (x) => x % 2 === 1) // => [1, 3]
R.filter.indexed([1, 2, 3], (x, i, array) => x % 2 === 1) // => [1, 3]

R.pipe(
  [1, 2, 3],
  R.filter((x) => x % 2 === 1)
) // => [1, 3]

[intersection数组交集][p]

返回两个数组的交集

用法:

  • R.intersection(array, other)
  • R.intersection(other)(array)

例子:

R.intersection([1, 2, 3], [2, 3, 5]) // => [2, 3]

R.intersection([2, 3, 5])([1, 2, 3]) // => [2, 3]

[sample数组随机取样][p]

根据取样数从数组中随机挑选一份子集

用法:

  • R.sample(array, sampleSize)
  • R.sample(sampleSize)(array);

例子:

R.sample(["hello", "world"], 1); // => ["hello"] // typed string[]
R.sample(["hello", "world"] as const, 1); // => ["world"] // typed ["hello" | "world"]

R.sample(1)(["hello", "world"]); // => ["hello"] // typed string[]
R.sample(1)(["hello", "world"] as const); // => ["world"] // typed ["hello" | "world"]

[shuffle数组洗牌][p]

数组重新随机打乱顺序后返回

用法:

  • R.shuffle(array);
  • R.shuffle()(array);

例子:

R.shuffle([4, 2, 7, 5]); // => [7, 5, 4, 2]

R.pipe([4, 2, 7, 5], R.shuffle()); // => [7, 5, 4, 2]

[difference根据另一个数组来排除值][p]

根据另一个数组来排除值

用法:

  • R.difference(array, other)
  • R.difference(other)(array)

例子:

R.difference([1, 2, 3, 4], [2, 5, 3]) // => [1, 4]

R.difference([2, 5, 3])([1, 2, 3, 4]) // => [1, 4]
R.pipe(
  [1, 2, 3, 4, 5, 6], // only 4 iterations
  R.difference([2, 3]),
  R.take(2)
) // => [1, 4]

[differenceWith根据另一个数组来排除值][p]

  • 根据另一个数组来排除值
  • 元素的比较由自定义的比较器来进行

用法:

  • R.differenceWith(array, other, isEquals)
  • R.differenceWith(other, isEquals)(array)

参数:

  • isEquals: (a, b) => Boolean; isEqual是一个比较方法,a和b分别是两个数组内的元素,结果返回这两个元素是否相等

例子:

R.differenceWith(
  [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }],
  [{ a: 2 }, { a: 5 }, { a: 3 }],
  (arr1, arr2) => arr1.a == arr2.a
) // => [{a: 1}, {a: 4}]

R.differenceWith(
  [{ a: 2 }, { a: 5 }, { a: 3 }],
  R.isDeepEqual
)([{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]) // => [{a: 1}, {a: 4}]
R.pipe(
  [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }, { a: 6 }], // only 4 iterations
  R.differenceWith([{ a: 2 }, { a: 3 }], R.isDeepEqual),
  R.take(2)
) // => [{a: 1}, {a: 4}]

[drop移除前n个元素][p]

移除数组的前n个元素

用法:

  • R.drop(array, n)
  • R.drop(n)(array)

例子:

R.drop([1, 2, 3, 4, 5], 2) // => [3, 4, 5]

R.drop(2)([1, 2, 3, 4, 5]) // => [3, 4, 5]

[dropFirstBy对数组排序后移除前n个元素]

根据提供的排序条件从数据中删除前n个项目。这样可以避免在删除项目之前对数组进行排序。这个函数的复杂度是O(Nlogn). 其中N是数组长度

用法:

  • R.dropFirstBy(array, n, ...rules);
  • R.dropFirstBy(n, ...rules)(array

例子:

R.dropFirstBy(["aa", "aaaa", "a", "aaa"], 2, (x) => x.length); // => ['aaa', 'aaaa']

R.pipe(
  ["aa", "aaaa", "a", "aaa"],
  R.dropFirstBy(2, (x) => x.length),
); // => ['aaa', 'aaaa']

[dropWhile根据断言移除前n个元素]

从前往后移除数组元素,直到断言返回false. 返回剩下的元素数组(包含false的元素)

用法:

  • R.dropWhile(array, predicate);
  • R.dropWhile(predicate)(array)

例子:

R.dropWhile([1, 2, 10, 3, 4], (x) => x < 10); // => [10, 3, 4]

R.pipe(
  [1, 2, 10, 3, 4],
  R.dropWhile((x) => x < 10),
); // => [10, 3, 4]

[dropLast移除后n个元素]

移除数组的后n个元素

用法:

  • R.dropLast(array, n)
  • R.dropLast(n)(array)

例子:

R.dropLast([1, 2, 3, 4, 5], 2) // => [1, 2, 3]

R.dropLast(2)([1, 2, 3, 4, 5]) // => [1, 2, 3]

[dropLastWhile根据断言移除后n个元素]

从后往前移除数组元素,直到断言返回false. 返回剩下的元素数组(包含false的元素)

用法:

  • R.dropLastWhile(array, predicate);
  • R.dropLastWhile(predicate)(array)

例子:

R.dropLastWhile([1, 2, 10, 3, 4], (x) => x < 10); // => [1, 2, 10]

R.pipe(
  [1, 2, 10, 3, 4],
  R.dropLastWhile((x) => x < 10),
); // => [1, 2, 10]

[unique数组去重][p]

  • 返回一个新数组,其中只包含原始列表中每个元素的一个副本。
  • 对象元素通过引用地址进行比较。

用法:

  • R.unique(array)

例子:

R.unique([1, 2, 2, 5, 1, 6, 7]) // => [1, 2, 5, 6, 7]

const zs = {name: '张三'}
R.unique([zs, zs, {name: '李四'}, {name: '张三', age: 14}])  // 引用地址进行比较
// '[{"name":"张三"},{"name":"李四"},{"name":"张三","age":14}]'

R.unique([{name: '张三'}, {name: '张三'}, {name: '李四'}, {name: '张三', age: 14}]) // 引用地址进行比较
// '[{"name":"张三"},{"name":"张三"},{"name":"李四"},{"name":"张三","age":14}]'

R.pipe(
  [1, 2, 2, 5, 1, 6, 7], // only 4 iterations
  R.unique(),
  R.take(3)
) // => [1, 2, 5]

[uniqueBy 数组去重][p]

  • 返回一个新数组,该数组只包含由函数转换后的值的唯一副本。
  • 对象元素通过引用地址进行比较。(参数unique)

用法:

  • R.uniqueBy(array, fn)

例子:

R.uniqueBy(
  [{ n: 1 }, { n: 2 }, { n: 2 }, { n: 5 }, { n: 1 }, { n: 6 }, { n: 7 }],
  (obj) => obj.n
) // => [{n: 1}, {n: 2}, {n: 5}, {n: 6}, {n: 7}]
R.pipe(
  [{ n: 1 }, { n: 2 }, { n: 2 }, { n: 5 }, { n: 1 }, { n: 6 }, { n: 7 }], // only 4 iterations
  R.uniqueBy((obj) => obj.n),
  R.take(3)
) // => [{n: 1}, {n: 2}, {n: 5}]

[uniqWith 数组去重]

  • 返回一个去重的新数组,是否重复由用户自定义的比较器决定。

用法:

  • R.uniqWith(array, isEquals)
  • R.uniqWith(isEquals)(array)

例子:

R.uniqWith(
  [{ a: 1 }, { a: 2 }, { a: 2 }, { a: 5 }, { a: 1 }, { a: 6 }, { a: 7 }],
  R.isDeepEqual
) // => [{a: 1}, {a: 2}, {a: 5}, {a: 6}, {a: 7}]

R.uniqWith(R.isDeepEqual)([
  { a: 1 },
  { a: 2 },
  { a: 2 },
  { a: 5 },
  { a: 1 },
  { a: 6 },
  { a: 7 },
]) // => [{a: 1}, {a: 2}, {a: 5}, {a: 6}, {a: 7}]
R.pipe(
  [{ a: 1 }, { a: 2 }, { a: 2 }, { a: 5 }, { a: 1 }, { a: 6 }, { a: 7 }], // only 4 iterations
  R.uniqWith(R.isDeepEqual),
  R.take(3)
) // => [{a: 1}, {a: 2}, {a: 5}]

[concat数组拼接]

联合两个数组

用法:

  • R.concat(arr1, arr2)
  • R.concat(arr2)(arr1)

例子:

R.concat([1, 2, 3], ['a']) // [1, 2, 3, 'a']

R.concat(['a'])([1, 2, 3]) // [1, 2, 3, 'a']

[zip两个数组内部元素组合]

把两个数组组合成二维数组,把相同索引处的值组合在一起。返回的数组长度以提供的两个数组中最短的那个为主

用法:

  • R.zip(first, second)
  • R.zip(second)(first)

例子:

R.zip([1, 2, 3], ['a', 'b']) // => [[1, 'a'], [2, 'b']]

R.zip(['a', 'b'])([1, 2]) // => [[1, 'a'], [2, 'b']]

[zipWith两个数组内部元素组合]

通过自定义函数把两个数组组合到一起

用法:

  • R.zipWith(first, second, fn)

例子:

R.zipWith(['1', '2', '3'], ['a', 'b', 'c'], (a, b) => a + b) // => ['1a', '2b', '3c']

R.zipWith((a, b) => a + b)(['1', '2', '3'], ['a', 'b', 'c']) // => ['1a', '2b', '3c']

[chunk按固定长度分多块]

把数组按固定长度分割,如果最后一块数组的长度不够,则只保留剩下的值

用法:

  • R.chunk(array, size)
  • R.chunk(size)(array)

参数:

  • array (Array ): 要分割的数据
  • size (Number ): 要分割的长度

返回:

(Array): 返回新的二维数组

例子:

R.chunk(['a', 'b', 'c', 'd'], 2) // => [['a', 'b'], ['c', 'd']]
R.chunk(['a', 'b', 'c', 'd'], 3) // => [['a', 'b', 'c'], ['d']]

R.chunk(2)(['a', 'b', 'c', 'd']) // => [['a', 'b'], ['c', 'd']]
R.chunk(3)(['a', 'b', 'c', 'd']) // => [['a', 'b', 'c'], ['d']]

[groupBy分组拆分为对象][i]

将集合分组拆分为对象,并根据通过fn运行每个值的结果进行分组。

用法:

  • R.groupBy(array, fn)
  • R.groupBy(fn)(array)

例子:

R.groupBy(['one', 'two', 'three'], (x) => x.length) // => {3: ['one', 'two'], 5: ['three']}

R.pipe(
  ['one', 'two', 'three'],
  R.groupBy((x) => x.length)
) // => {3: ['one', 'two'], 5: ['three']}

[partition根据断言分割为两部分][i]

分割数组为两部分,第一部分是匹配断言的集合。第二部分是未匹配断言的集合

用法:

  • R.partition(array, fn)
  • R.partition(fn)(array)

例子:

R.partition(['one', 'two', 'forty two'], (x) => x.length === 3) // => [['one', 'two'], ['forty two']]

R.pipe(
  ['one', 'two', 'forty two'],
  R.partition((x) => x.length === 3)
) // => [['one', 'two'], ['forty two']]

[splitAt根据索引分割为两部分]

根据索引分割数组为两部分

用法:

  • R.splitAt(array, index)
  • R.splitAt(index)(array)

例子:

R.splitAt([1, 2, 3], 1) // => [[1], [2, 3]]
R.splitAt([1, 2, 3, 4, 5], -1) // => [[1, 2, 3, 4], [5]]

[splitWhen根据索引分割为两部分]

根据断言第一次返回true的元素的索引分割数组为两部分

用法:

  • R.splitWhen(array, fn)
  • R.splitWhen(fn)(array)

例子:

R.splitWhen([1, 2, 3], (x) => x === 2) // => [[1], [2, 3]]

R.splitWhen((x) => x === 2)([1, 2, 3]) // => [[1], [2, 3]]

[reverse倒置数组]

倒置数组

用法:

  • R.reverse(arr)
  • R.reverse()(array)

例子:

R.reverse([1, 2, 3]) // [3, 2, 1]

R.reverse()([1, 2, 3]) // [3, 2, 1]

[sort数组排序]

数组排序, 这个比较函数一次接收两个值,并且返回一个number, 如果正向排序就返回负数,如果反向排序就返回正数,如果相等不用换位置就返回0

用法:

  • R.sort(items, (a, b) => Number)
  • R.sort(cmp)(items)

例子:

R.sort([4, 2, 7, 5], (a, b) => a - b) // => [2, 4, 5, 7]

R.pipe(
  [4, 2, 7, 5],
  R.sort((a, b) => a - b)
) // => [2, 4, 5, 7]

[sortBy数组排序]

  • 显式声明排序方式asc / desc (不指定就默认asc)
  • 可以多个排序函数一起作用,最前面的优先级最高

用法:

  • R.sortBy(array, ...sorts)
  • R.sortBy(...sorts)(array)

参数:

  • 参数名 (参数类型): 参数描述

返回:

(返回类型): 返回描述

例子:

R.sortBy([{ a: 1 }, { a: 3 }, { a: 7 }, { a: 2 }], (x) => x.a)
// => [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 7 }]

R.sortBy(
  [
    { color: 'red', weight: 2 },
    { color: 'blue', weight: 3 },
    { color: 'green', weight: 1 },
    { color: 'purple', weight: 1 },
  ],
  [(x) => x.weight, 'asc'],
  (x) => x.color
)
// =>
//   {color: 'purple', weight: 1},
//   {color: 'green', weight: 1},
//   {color: 'red', weight: 2},
//   {color: 'blue', weight: 3},

[flat扁平化数组][p]

扁平化第一层数组

用法:

  • R.flat(data); \ R.flat(data, depth);
  • R.flat()(data); \ R.flat(depth)(data);

例子:

R.flat([[1, 2], [3, 4], [5], [[6]]]); // => [1, 2, 3, 4, 5, [6]]
R.flat([[[1]], [[2]]], 2); // => [1, 2]

R.pipe([[1, 2], [3, 4], [5], [[6]]], R.flat()); // => [1, 2, 3, 4, 5, [6]]
R.pipe([[[1]], [[2]]], R.flat(2)); // => [1, 2]

[flatMap映射数组并扁平化结果][p]

使用定义的回调函数映射数组中的每个元素,并展平映射的结果。

用法:

  • R.flatMap(array, fn);
  • R.flatMap(fn)(array);

例子:

R.flatMap([1, 2, 3], (x) => [x, x * 10]); // => [1, 10, 2, 20, 3, 30]

R.pipe(
  [1, 2, 3],
  R.flatMap((x) => [x, x * 10]),
); // => [1, 10, 2, 20, 3, 30]

[range生成固定范围的number数组]

返回一个Number数组,范围时从start(包含)到end(不包含)

用法:

  • range(start, end)

例子:

R.range(1, 5) // => [1, 2, 3, 4]

[length统计集合长度]

返回集合长度

用法:

  • R.length(array);
  • R.length()(array);

例子:

R.length([1, 2, 3]); // => 3

R.pipe([1, 2, 3], R.length()); // => 3

[join数组拼接为字符串]

把数组拼接为一个字符串。如果数组是元祖。这字符串结果是stricter(更严格)的

用法:

  • R.join(data, glue);
  • R.join(glue)(data);

例子:

R.join([1, 2, 3], ","); // => "1,2,3" (typed `string`)
R.join(["a", "b", "c"], ""); // => "abc" (typed `string`)
R.join(["hello", "world"] as const, " "); // => "hello world" (typed `hello world`)

R.pipe([1, 2, 3], R.join(",")); // => "1,2,3" (typed `string`)
R.pipe(["a", "b", "c"], R.join("")); // => "abc" (typed `string`)
R.pipe(["hello", "world"] as const, R.join(" ")); // => "hello world" (typed `hello world`)

[swapIndices交换元素位置]

在提供的两个索引处交换数组或字符串中两个元素的位置

用法:

  • swapIndices(data, index1, index2);
  • swapIndices(index1, index2)(data);

例子:

swapIndices(["a", "b", "c"], 0, 1); // => ['b', 'a', 'c']
swapIndices("abc", 0, 1); // => 'bac'

swapIndices(0, 1)(["a", "b", "c"]); // => ['b', 'a', 'c']
swapIndices(0, -1)("abc"

[intersectionWith获取数组交叉部分]

返回基于自定义比较器函数的相交值列表,自定义比较器函数用于比较两个数组元素

用法:

  • R.intersectionWith(array, other, comparator);
  • R.intersectionWith(other, comparator)(array);

例子:

R.intersectionWith(
  [
    { id: 1, name: "Ryan" },
    { id: 3, name: "Emma" },
  ],
  [3, 5],
  (a, b) => a.id === b,
); // => [{ id: 3, name: 'Emma' }]

R.intersectionWith(
  [3, 5],
  (a, b) => a.id === b,
)([
  { id: 1, name: "Ryan" },
  { id: 3, name: "Emma" },
]); // => [{ id: 3, name: 'Emma' }]

[isIncludedIn数据A是否包含在数据B中]

这是对Array.protptype.includes和Set.propotype.has的封装

用法:

  • R.isIncludedIn(data, container);
  • R.isIncludedIn(container)(data);

例子:

R.isIncludedIn(2, [1, 2, 3]); // => true
R.isIncludedIn(4, [1, 2, 3]); // => false

const data = "cat" as "cat" | "dog" | "mouse";
R.isIncludedIn(data, ["cat", "dog"] as const); // true (typed "cat" | "dog");

// -----------------

R.pipe(2, R.isIncludedIn([1, 2, 3])); // => true
R.pipe(4, R.isIncludedIn([1, 2, 3])); // => false

const data = "cat" as "cat" | "dog" | "mouse";
R.pipe(data, R.isIncludedIn(["cat", "dog"] as const)); // => true (typed "cat" | "dog");

七.Function

[pipe函数组合-左到右]

组合函数,执行顺序为从左到右,左边一个函数的返回值是下一个函数的输入值(参数)

用法:

  • R.pipe(data, op1, op2, op3)

例子:

R.pipe(
  [1, 2, 3, 4],
  R.map((x) => x * 2),
  (arr) => [arr[0] + arr[1], arr[2] + arr[3]]
) // => [6, 14]

[pipedpipe的数据在后版本]

piped 的数据在后版本 第一个方法必须给类型注释,后面的方法会根据前面的自动推断

用法:

  • R.piped(...ops)(data);

例子:

R.filter(
  [{ a: 1 }, { a: 2 }, { a: 3 }],
  R.piped(R.prop("a"), (x) => x % 2 === 0),
); // => [{ a: 2 }]

[allPass断言组合-都通过]

对于输入的数据,是否所有的断言都通过

用法:

  • R.allPass(data, fns)
  • R.allPass(fns)(data)

参数:

  • data (any): 要断言的数据
  • fns (Array<Function>): 断言方法数组

返回:

(Boolean): 是否所有的断言都通过

例子:

const isDivisibleBy3 = (x: number) => x % 3 === 0
const isDivisibleBy4 = (x: number) => x % 4 === 0
const fns = [isDivisibleBy3, isDivisibleBy4]

R.allPass(12, fns) // => true
R.allPass(8, fns) // => false

R.allPass(fns)(12) // => true
R.allPass(fns)(8) // => false

[anyPass断言组合-任意一个通过]

对于输入的数据,是否有任意一个断言通过

用法:

  • R.anyPass(data, fns)
  • R.anyPass(fns)(data)

参数:

  • data (any): 要断言的数据
  • fns (Array<Function>): 断言方法数组

返回:

(Boolean): 是否所有的断言都通过

例子:

const isDivisibleBy3 = (x: number) => x % 3 === 0
const isDivisibleBy4 = (x: number) => x % 4 === 0
const fns = [isDivisibleBy3, isDivisibleBy4]

R.anyPass(8, fns) // => true
R.anyPass(11, fns) // => false

R.anyPass(fns)(8) // => true
R.anyPass(fns)(11) // => false

[once只执行一次的函数]

创建只执行一次的函数,后面的重复调用都只会返回第一次调用的结果

用法:

  • R.once(fn)

例子:

const initialize = R.once(createApplication)
initialize()
initialize()
// => `createApplication` is invoked once

[times一次执行n次fn函数]

执行n次fn函数,并把每次函数返回的值并为一个数组返回.fn接收的参数是0~n-1

用法:

  • R.time(n, fn)
  • R.time(fn)(n)

例子:

times(identity, 5) //=> [0, 1, 2, 3, 4]

times(5)(identity) //=> [0, 1, 2, 3, 4]

[identity返回原参数]

把传入的参数再返回出去

用法:

  • R.identity(data)

例子:

R.identity('foo') // => 'foo'

[tap执行某个方法后返回原参数]

1.调用具有给定值的给定函数,然后返回给定值。所提供函数的返回值将被忽略 2.这允许“窃听”管道中的函数序列,以对中间结果执行副作用。

用法:

  • R.tap(value, fn
  • R.tap(fn)(value);

例子:

R.tap("foo", console.log); // => "foo"

R.pipe(
  [-5, -1, 2, 3],
  R.filter((n) => n > 0),
  R.tap(console.log), // prints [2, 3]  这里console.log返回的是Undefined.但tap放返回的依然是他接收到的数据
  R.map((n) => n * 2),
); // => [4, 6]

[purry创建data-first和data-last签名的函数]

创建data-first和data-last签名的函数, purry是一个动态函数并且没有类型安全,它应该被一个拥有合适类型的函数包装起来

用法:

  • R.purry(fn, arguments)

例子:

function _findIndex(array: any, fn: any) {
  for (let i = 0; i < array.length; i++) {
    if (fn(array[i])) {
      return i;
    }
  }
  return -1;
}

// data-first
function findIndex<T>(array: T[], fn: (item: T) => boolean): number;

// data-last
function findIndex<T>(fn: (item: T) => boolean): (array: T[]) => number;

function findIndex() {
  return R.purry(_findIndex, arguments);
}

findIndex([1,2,3], item => item == 2) // 1
findIndex(item => item == 2)([1,2,3]) // 1

[conditional条件匹配(switch)]

执行第一个匹配条件的函数。类似于switch

用法:

  • R.conditional(data, ...cases);
  • R.conditional(...cases)(data)

例子:

const nameOrId = 3 as string | number;
R.conditional(
  nameOrId,
  [R.isString, (name) => `Hello ${name}`],
  [R.isNumber, (id) => `Hello ID: ${id}`],
  R.conditional.defaultCase(
    (something) => `Hello something (${JSON.stringify(something)})`,
  ),
); //=> 'Hello ID: 3'

const nameOrId = 3 as string | number;
R.pipe(
  nameOrId,
  R.conditional(
    [R.isString, (name) => `Hello ${name}`],
    [R.isNumber, (id) => `Hello ID: ${id}`],
    R.conditional.defaultCase(
      (something) => `Hello something (${JSON.stringify(something)})`,
    ),
  ),
); //=> 'Hello ID: 3'

[debounce 去抖动]

包装一个函数,如果这个函数在短时间内调用多次,之后执行一次;

用法:

  • R.debounce(func, options);

参数:

  • options: {timing: 'both'|'leading'| 'trailing', waitMs: number}
  • options.timing: 调用的位置 leading 头部调用,trailing 尾部调用,both 首尾各调用一次
  • options.waitMs: 冷却时间

返回值:

{
  call: (...args) => any,  // 调用被包装的函数并传参
  cancel: () => void,  // 如果在冷却期调用,则取消冷却期结束后应该调用的函数(但不影响下一轮的冷却期)
  flush: () => void, // 如果在冷却期调用,则立即触发冷却期结束事件
  isPending: boolean, // 是否处于冷却期
  cacheValue: any, // 上一次被包装函数调用后的返回值(每一次调用被包装函数都会把它的返回值缓存下来)
}

例子:

const debouncer = debounce(identity, { timing: "trailing", waitMs: 1000 });
const result1 = debouncer.call(1); // => undefined
const result2 = debouncer.call(2); // => undefined
// after 1 second
const result3 = debouncer.call(3); // => 2
// after 1 second
debouncer.cachedValue; // => 3

[doNothing接收任意参数但不操作]

接收任意参数但不操作,并且返回void

用法:

  • R.doNothing()

例子:

myApi({ onSuccess: handleSuccess, onError: R.doNothing() });
myApi({ onSuccess: isDemoMode ? R.doNothing() : handleSuccess });

八.Guard 守卫

[isDeepEqual深度比较两个值是否相等]

深度比较两个值是否相等; 单一值用 === 数组和对象都会深度遍历去比较的 时间Date等特殊值也会取它的值来比较的(而不是比较对象的内存地址应用)

用法:

  • R.isDeepEqual(data, other);
  • R.isDeepEqual(other)(data);

例子:

R.isDeepEqual(1, 1); //=> true
R.isDeepEqual(1, "1"); //=> false
R.isDeepEqual([1, 2, 3], [1, 2, 3]); //=> true

R.pipe(1, R.isDeepEqual(1)); //=> true
R.pipe(1, R.isDeepEqual("1")); //=> false
R.pipe([1, 2, 3], R.isDeepEqual([1, 2, 3])); //=> true

[isArray是否是数组]

用于检查传递的参数是否为数组,并相应地缩小其类型

用法:

  • R.isArray(data)

例子:

R.isArray([5]) //=> true
R.isArray([]) //=> true
R.isArray('somethingElse') //=> false

[isBoolean是否是布尔值]

用于检查传递的参数是否为布尔值,并相应地缩小其类型

用法:

  • R.isBoolean(data)

例子:

R.isBoolean(true) //=> true
R.isBoolean(false) //=> true
R.isBoolean('somethingElse') //=> false

[isDate是否是时间]

用于检查传递的参数是否为时间,并相应地缩小其类型

用法:

  • R.isDate(data)

例子:

R.isDate(new Date()) //=> true
R.isDate('somethingElse') //=> false

[isDefined是否已定义]

用于检查传递的参数是否已定义,并相应地缩小其类型

用法:

  • R.isDefined(data)

例子:

R.isDefined('string') //=> true
R.isDefined(null) //=> false
R.isDefined(undefined) //=> false

[isError是否是Error对象]

用于检查传递的参数是否是Error,并相应地缩小其类型

用法:

  • R.isError(data)

例子:

R.isError(new Error('message')) //=> true
R.isError('somethingElse') //=> false

[isFunction是否是函数]

用于检查传递的参数是否是函数,并相应地缩小其类型

用法:

  • R.isFunction(data)

例子:

R.isFunction(() => {}) //=> true
R.isFunction('somethingElse') //=> false

[isNullish是否是空]

用于检查传递的参数是否是空(null \ undefined),并相应地缩小其类型

用法:

  • R.isNullish(data)

例子:

R.iisNullish(undefined) //=> true
R.iisNullish(null) //=> true
R.iisNullish('somethingElse') //=> false

[isNonNullish是否是有效值]

用于检查传递的参数是否非null和非undefined,并相应地缩小其类型

用法:

  • R.isNonNullish(data)

例子:

R.isNonNullish("string"); //=> true
R.isNonNullish(null); //=> false
R.isNonNullish(undefined); //=> false

[isNonNull是否非null]

用于检查传递的参数是否非null,并相应地缩小其类型 主要undefined也是非null

用法:

  • R.isNonNull(data)

例子:

R.isNonNull("string"); //=> true
R.isNonNull(null); //=> false
R.isNonNull(undefined); //=> true

[isNot对守卫函数取反]

把原守卫函数当断言使用,并返回一个反向的守卫函数

用法:

  • R.isNot(R.isTruthy)(data)

例子:

R.isNot(R.isTruthy)(false) //=> true
R.isNot(R.isTruthy)(true) //=> false

[isNumber是否是数字]

用于检查传递的参数是否是数字,并相应地缩小其类型

用法:

  • R.isNumber(data)

例子:

R.isNumber(1) //=> true
R.isNumber('notANumber') //=> false
R.isNumber('1') //=> false

[isObjectType是否是对象类型]

需要注意的是,在JavaScript中,许多实体都被视为对象,如Arrays, Classes, RegExps, Maps, Sets, Dates, URLs, Promise, Errors等。 虽然从技术上讲,null也是一个对象,但此函数不将null视为对象,因此更容易缩小null的范围。 对于普通对象,考虑用 isPlainObject 代替

用法:

  • R.isObjectType(data)

例子:

// true
R.isObjectType({}); //=> true
R.isObjectType([]); //=> true
R.isObjectType(Promise.resolve("something")); //=> true
R.isObjectType(new Date()); //=> true
R.isObjectType(new Error("error")); //=> true

// false
R.isObjectType("somethingElse"); //=> false
R.isObjectType(null); //=> false

[isPlainObject是否是普通对象]

一般指非Arrays, Classes, RegExps, Maps, Sets, Dates, URLs, Promise, Errors等 的 普通对象。

用法:

  • R.isPlainObject(data)

例子:

// true
R.isPlainObject({}); //=> true
R.isPlainObject({ a: 123 }); //=> true
R.isPlainObject({ a: 123, abj: { key1: new Date() } }); //=> true

// false
R.isPlainObject([]); //=> false
R.isPlainObject(Promise.resolve("something")); //=> false
R.isPlainObject(new Date()); //=> false
R.isPlainObject(new Error("error")); //=> false
R.isPlainObject("somethingElse"); //=> false
R.isPlainObject(null); //=> false

[isPromise是否是Promise]

用于检查传递的参数是否是Promise,并相应地缩小其类型

用法:

  • R.isPromise(data)

例子:

R.isPromise(Promise.resolve(5)) //=> true
R.isPromise(Promise.reject(5)) //=> true
R.isPromise('somethingElse') //=> false

[isString是否是字符串]

用于检查传递的参数是否是字符串,并相应地缩小其类型

用法:

  • R.isString(data)

例子:

R.isString('string') //=> true
R.isString(1) //=> false

[isTruthy是否是truthy]

用于检查传递的参数是否是truthy,并相应地缩小其类型

用法:

  • R.isTruthy(data)

例子:

R.isTruthy('somethingElse') //=> true
R.isTruthy([]) //=> true
R.isTruthy(null) //=> false
R.isTruthy(undefined) //=> false
R.isTruthy(false) //=> false
R.isTruthy(0) //=> false
R.isTruthy('') //=> false
R.isTruthy(NaN) //=> false

[isSymbol是否是isSymbol]

用于检查传递的参数是否是Symbol,并相应地缩小其类型

用法:

  • R.isSymbol(data)

例子:

R.isSymbol(Symbol("foo")); //=> true
R.isSymbol(1); //=> false