30秒就能看懂的JavaScript 代码片段

689 阅读10分钟
原文链接: www.liayal.com

使用 Ctrl + F or command + F来搜索代码片段

目录

🔌 Adapter

ary(指定函数参数个数)

创建一个函数且接受最多 n 个参数,忽略多余参数。

调用传入的函数 fn 并传入给定的 n 个参数。

参数通过 Array.slice(0,n) 截取,并使用(…)解构。

const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
// 示例
const firstTwoMax = ary(Math.max, 2);
[[2, 6, 'a'], [8, 4, 6], [10]].map(x => firstTwoMax(...x)); // [6, 8, 10]

call(函数组合)

给定一个 key 和一个 set 作为参数,给定上下文时调用它们。主要用于函数组合。

使用闭包以存储的参数调用存储的 key 。

const call = (key, ...args) => context => context[key](...args);
// 示例
Promise.resolve([1, 2, 3])
  .then(call('map', x => 2 * x))
  .then(console.log); //[ 2, 4, 6 ]
const map = call.bind(null, 'map');
Promise.resolve([1, 2, 3])
  .then(map(x => 2 * x))
  .then(console.log); //[ 2, 4, 6 ]

collectInto(将接受数组的函数更改为可变参数函数。)

将接受数组的函数更改为可变参数函数。

给定一个函数,返回一个闭包,将所有输入收集到一个接受函数的数组中。

const collectInto = fn => (...args) => fn(args);
// 示例
const Pall = collectInto(Promise.all.bind(Promise));
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = new Promise(resolve => setTimeout(resolve, 2000, 3));
Pall(p1, p2, p3).then(console.log); // [1, 2, 3] (after about 2 seconds)

flip(翻转函数参数)

Flip接受函数作为参数,然后将函数第一个参数作为最后一个参数。

返回一个包含可变参数输入的闭包,并且在应用其余参数之前将最后一个参数拼接成第一个参数。

const flip = fn => (first, ...rest) => fn(...rest, first);
// 示例
let a = { name: 'John Smith' };
let b = {};
const mergeFrom = flip(Object.assign);
let mergePerson = mergeFrom.bind(null, a);
mergePerson(b); // == b
b = {};
Object.assign(b, a); // == b

over(同一参数调用多个函数)

创建一个函数,用它接收到的参数调用每个提供的函数,并返回结果。

使用 Array.map()和 Function.apply() 将给定的参数应用到每个函数。

const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args));
// 示例
const minMax = over(Math.min, Math.max);
minMax(1, 2, 3, 4, 5); // [1,5]

overArgs(参数转换器)

给定一个函数,通过指定函数转变其参数后再调用。

使用Array.map()与展开操作符(…),通过transforms来转换参数并传递给 fn 。

const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val)));
// 示例
let square = a => a * a;
let doubled = b => 2 * b;
var func = overArgs(
  function(x, y) {
    return [x, y];
  },
  [square, doubled]
);
func(9, 3); // [81, 6]

pipeAsyncFunctions(顺序执行异步函数)

从左到右的执行异步函数组合。
使用Array.reduce()与展开操作符(…),从左到右使用Promise.then()执行函数组合。

这些函数可以返回:简单值,Promise的组合或者定义为通过await返回的异步。

所有函数必须是一元函数。

const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg));
// 示例
const sum = pipeAsyncFunctions(
  x => x + 1,
  x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)),
  x => x + 3,
  async x => (await x) + 4
);
(async () => {
  console.log(await sum(5)); // 15 (after one second)
})();

pipeFunctions(从左到右的执行函数组合)

执行从左到右的函数组合。

使用 Array.reduce() 与展开操作符 (…) 来执行从左到右的函数组合。第一个(最左边的)函数可以接受一个或多个参数;其余的函数必须是一元函数。

const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
// 示例
const add5 = x => x + 5;
const multiply = (x, y) => x * y;
const multiplyAndAdd5 = pipeFunctions(multiply, add5);
multiplyAndAdd5(5, 2); // 15

promisify(柯里化一个 Promise 函数)

转换一个异步函数,以返回一个 promise 。

使用柯里化返回一个函数,这个函数返回一个调用原始函数的 Promise 。 使用 …rest 运算符传入所有参数。

在 Node 8+ 中,你可以使用 util.promisify

const promisify = func => (...args) =>
  new Promise((resolve, reject) =>
    func(...args, (err, result) => (err ? reject(err) : resolve(result)))
  );
// 示例
const delay = promisify((d, cb) => setTimeout(cb, d));
delay(2000).then(() => console.log('Hi!')); // Promise resolves after 2s

rearg(参数重新排列)

创建一个函数调用给定的函数,给定的函数参数按照指定的索引排列。

基于 indexes 使用 Array.reduce() 和 Array.indexOf() 重排参数,使用展开操作符 (…) 向给定函数传参。

const rearg = (fn, indexes) => (...args) =>
  fn(
    ...args.reduce(
      (acc, val, i) => ((acc[indexes.indexOf(i)] = val), acc),
      Array.from({ length: indexes.length })
    )
  );
// 示例
var rearged = rearg(
  function(a, b, c) {
    return [a, b, c];
  },
  [2, 0, 1]
);
rearged('b', 'c', 'a'); // ['a', 'b', 'c']

spreadOver(将参数数组映射到该函数的输入)

接受一个可变参数函数并返回一个闭包,该闭包接受一个参数数组映射到该函数的输入。

使用闭包和展开运算符 (…) 将参数数组映射到函数的输入。

const spreadOver = fn => argsArr => fn(...argsArr);
// 示例
const arrayMax = spreadOver(Math.max);
arrayMax([1, 2, 3]); // 3

unary(只接受一个参数的函数)

创建一个最多接受一个参数的函数,忽略任何附加参数。

调用给定函数,只传入第一个参数。

const unary = fn => val => fn(val);
// 示例
['6', '8', '10'].map(unary(parseInt)); // [6, 8, 10]

📚 Array

chunk(数组分块)

把一个数组分块成指定大小的小数组。

使用 Array.from() 创建一个新的数组,它的长度就是生成 chunk(块) 的数量。 使用 Array.slice() 将新数组的每个元素映射到长度为 size 的 chunk 中。 如果原始数组不能均匀分割,最后的 chunk 将包含剩余的元素。

const chunk = (arr, size) =>
  Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
    arr.slice(i * size, i * size + size)
  );
// 示例
chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]

compact(过滤掉数组中所有假值元素)

从数组中移除 falsey 值元素。

使用 Array.filter() 过滤掉数组中所有 假值元素(false, null, 0, “”, undefined, 和 NaN)。

const compact = arr => arr.filter(Boolean);
// 示例
compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); // [ 1, 2, 3, 'a', 's', 34 ]

countBy(根据条件对数组分组)

根据给定的函数对数组的元素进行分组,并返回每个组中元素的数量。

使用 Array.map() 将数组的值映射到函数或属性名称。 使用Array.reduce() 创建一个对象,其中的键是从映射的结果中产生的。

const countBy = (arr, fn) =>
  arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
    acc[val] = (acc[val] || 0) + 1;
    return acc;
  }, {});
// 示例
countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2}
countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1}

countOccurrences(计数数组中某个值的出现次数)

计算数组中值的出现次数。

每次遇到数组中的某个特定值时,使用 Array.reduce() 来递增计数器。

const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a + 0), 0);
// 示例
countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3

deepFlatten(深度平铺数组)

深度平铺一个数组。

使用递归。 通过空数组([]) 使用 Array.concat() ,结合 展开运算符( … ) 来平铺数组。 递归平铺每个数组元素。

const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
// 示例
deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]

difference(数组比较)

返回两个数组之间的差异。

根据数组 b 创建一个 Set 对象,然后在数组 a 上使用 Array.filter() 方法,过滤出数组 b 中不包含的值。

const difference = (a, b) => {
  const s = new Set(b);
  return a.filter(x => !s.has(x));
};
// 示例
difference([1, 2, 3], [1, 2, 4]); // [3]

differenceBy(给定条件进行数组比较)

将给定函数应用于两个数组元素之后,返回两个数组之间的差异。

通过对 b 中的每个元素应用 fn 后创建一个 Set 对象,然后在数组 a 上使用 Array.filter() 和 fn ,只保留之前创建的集合中不包含的值。

const differenceBy = (a, b, fn) => {
  const s = new Set(b.map(v => fn(v)));
  return a.filter(x => !s.has(fn(x)));
};
// 示例
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ]

differenceWith(通过比较函数比较两个数组的差异)

过滤掉比较函数不返回true的数组中的所有值。
使用 Array.filter() 和 Array.findIndex() 来查找合适的值。

const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);
// 示例
differenceWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2]

drop(数组删除)

从左边删除n个元素,并返回新数组。
使用 Array.slice()从左侧删除指定数量的元素。

const drop = (arr, n = 1) => arr.slice(n);
// 示例
drop([1, 2, 3]); // [2,3]
drop([1, 2, 3], 2); // [3]
drop([1, 2, 3], 42); // []

dropRight(从右边删除数组)

从右边边删除n个元素,并返回新数组。
使用 Array.slice()从右侧删除指定数量的元素。

const dropRight = (arr, n = 1) => arr.slice(0, -n);
// 示例
dropRight([1, 2, 3]); // [1,2]
dropRight([1, 2, 3], 2); // [1]
dropRight([1, 2, 3], 42); // []

dropRightWhile(根据函数从右删除元素)

从数组末尾移除元素,直到传递的函数返回true。 返回数组中的其余元素。
循环访问数组,使用Array.slice()删除数组的最后一个元素,直到函数的返回值为true。 返回其余的元素。

const dropRightWhile = (arr, func) => {
  while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1);
  return arr;
};
// 示例
dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2]

dropWhile(根据函数删除元素)

删除数组中的元素,直到传递的函数返回true。 返回数组中的其余元素。
循环访问数组,使用Array.slice()删除数组的第一个元素,直到函数的返回值为true。 返回其余的元素。

const dropWhile = (arr, func) => {
  while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
  return arr;
};
// 示例
dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4]

everyNth( 获得数组中的每个第 n 个元素)

返回数组中的每个第 n 个元素。
使用 Array.filter() 创建一个包含给定数组的每个第 n 个元素的新数组。

const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
// 示例
everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ]

filterNonUnique(数组去重)

过滤掉数组中的重复值。
使用 Array.filter() 滤除掉重复值,使数组仅包含唯一值。

const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
// 示例
filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1,3,5]

findLast(获取符合条件的最后一个元素)

返回给定函数返回 true 的最后一个元素。
使用 Array.filter()移除 fn 返回 false的元素,Array.slice(-1)获取最后一个元素。

const findLast = (arr, fn) => arr.filter(fn).slice(-1)[0];
// 示例
findLast([1, 2, 3, 4], n => n % 2 === 1); // 3

findLastIndex(获取符合条件的最后一个元素索引)

返回给定函数返回 true 的最后一个元素的索引。
使用 Array.map() 将每个元素映射到具有索引和值的数组。 使用Array.filter() 移除fn返回 false 的元素,Array.slice(-1) 获取最后一个元素。

const findLastIndex = (arr, fn) =>
  arr
    .map((val, i) => [i, val])
    .filter(val => fn(val[1], val[0], arr))
    .slice(-1)[0][0];
// 示例
findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3)

flatten(平铺数组)

使用递归,为每个深度级别 depth 递减 1 。 使用 Array.reduce() 和 Array.concat() 来合并元素或数组。 基本情况下,depth 等于 1 停止递归。 省略第二个参数,depth 只能平铺到 1 (单层平铺) 的深度。

const flatten = (arr, depth = 1) =>
  depth != 1
    ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])
    : arr.reduce((a, v) => a.concat(v), []);
// 示例
flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]

forEachRight( 从数组的最后一个元素开始遍历数组)

从数组的最后一个元素开始,为每个数组元素执行一次提供的函数。
使用 Array.slice(0) 克隆给定的数组,Array.reverse() 反转数组,Array.forEach() 遍历这个反向数组。

const forEachRight = (arr, callback) =>
  arr
    .slice(0)
    .reverse()
    .forEach(callback);
// 示例
forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1'

未完待续…