logo 30 seconds of code Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less.



Array

all

如果提供的断言函数(predicate function)对集合中所有的元素测试都返回 true,那么 all 方法就返回 true。否则,返回 false

使用 Array.prototype.every() 测试集合中的所有元素是否基于 fn 返回 true。 省略第二个参数fn,使用 Boolean 作为默认值。

const all = (arr, fn = Boolean) => arr.every(fn);
all([4, 2, 3], x => x > 1); // true
all([1, 2, 3]); // true

allEqual

检查数组中的所有元素是否相等。

使用 Array.prototype.every() 检查数组中的所有元素是否与第一个元素相同。 使用严格比较运算符比较数组中的元素,该运算符不考虑 NaN 与自己不相等的情况。

const allEqual = arr => arr.every(val => val === arr[0]);
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true

any

如果提供的断言函数(predicate function)对集合中所有的元素测试,至少有一个返回 true,那么 any 方法就返回 true。否则,返回 false

使用 Array.prototype.some() 测试集合中的所有元素是否基于 fn 返回 true。 省略第二个参数fn,使用 Boolean 作为默认值。

const any = (arr, fn = Boolean) => arr.some(fn);
any([0, 1, 2, 0], x => x >= 2); // true
any([0, 0, 1, 0]); // true

arrayToCSV

将二维数组转换为逗号分隔值(CSV)字符串。

使用 Array.prototype.map()Array.prototype.join(delimiter) 将单个一维数组(行)组合成字符串。 使用 Array.prototype.join('\n') 将所有行组合成 CSV 字符串,用换行符分隔每一行。 省略第二个参数 delimiter ,以使用','的默认分隔符。

const arrayToCSV = (arr, delimiter = ',') =>
  arr
    .map(v => v.map(x => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x)).join(delimiter))
    .join('\n');
arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"'
arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"'
arrayToCSV([['a', '"b" great'], ['c', 3.1415]]); // '"a","""b"" great"\n"c",3.1415'

bifurcate

将值分成两组,如果 filter 中的元素为 true,则集合中对应的元素属于第一组;否则,它属于第二组。

基于 filter,使用 Array.prototype.reduce()Array.prototype.push() 向组添加元素。

const bifurcate = (arr, filter) =>
  arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); // [ ['beep', 'boop', 'bar'], ['foo'] ]

bifurcateBy

根据断言函数(predicate function)会将值分成两组,集合中的元素输入到断言函数中后,来确定元素属于哪一组。如果断言函数返回一个真值,则集合元素属于第一组;否则,它属于第二组。

const bifurcateBy = (arr, fn) =>
  arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);
bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); // [ ['beep', 'boop', 'bar'], ['foo'] ]

chunk

将数组分块成指定大小的较小数组。

使用 array.from() 创建一个新的数组,该数组的长度就是将要生成的块(chunk)的个数。 使用 array.prototype.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

从数组中删除为 false 的值。

使用 Array.prototype.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 .prototype.map() 将数组的值映射到函数或属性名称。 使用 Array.prototype.reduce() 创建一个对象,其中键(key)是从映射的结果中产生的。

const countBy = (arr, fn) =>
  arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => {
    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. prototype.reduce() 递增计数器。

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

deepFlatten

深度平铺一个数组。

使用递归。 使用 array. prototype.concat() 和空数组( [] ),结合 spread 操作符('...')将数组平铺。 递归平铺数组中的每个元素。

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

将提供的函数应用于两个数组的每个数组元素后,返回两个数组之间的差值。

fn 处理数组 b 中的每个元素后创建 Set,然后使用 Array.prototype.map() 映射 fn 处理数组 a 中的每个元素,最后应用Array.prototype.filter() 进行过滤。

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

differenceWith

过滤出数组中比较函数不返回 true 的所有值。

使用 Array.prototype.filter()Array.prototype.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.prototype.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.prototype.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.prototype.slice() 删除数组中第一个遇到函数返回的值为 true 位置的元素。 返回数组中剩余的元素。

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

dropWhile

移除数组中的元素,直到传递的函数返回 true 。 返回数组中剩余的元素。

循环遍历数组,使用 array.prototype.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

Returns every nth element in an array.

Use Array.prototype.filter() to create a new array that contains every nth element of a given array.

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

filterFalsy


Filters out the falsy values in an array.

Use Array.prototype.filter() to get an array containing only truthy values.


过滤数组中为假值(falsy)的元素。

使用 array .prototype.filter() 过滤后,数组中只包含为真值(truthy)的元素。

const filterFalsy = arr => arr.filter(Boolean);
filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1]

filterNonUnique

过滤掉数组中的非唯一值。

使用 Array.prototype.filter() 过滤非唯一值后,返回只包含唯一值的数组。

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

filterNonUniqueBy

根据提供的比较器(comparator)函数,过滤数组中的非唯一值。

基于比较器函数 fn ,使用 array .prototype.filter()array .prototype.every() 对数组过滤后,数组中只包含唯一值。

比较器函数接受四个参数:正在比较的两个元素的值及其索引。

const filterNonUniqueBy = (arr, fn) =>
  arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
filterNonUniqueBy(
  [
    { id: 0, value: 'a' },
    { id: 1, value: 'b' },
    { id: 2, value: 'c' },
    { id: 1, value: 'd' },
    { id: 0, value: 'e' }
  ],
  (a, b) => a.id == b.id
); // [ { id: 2, value: 'c' } ]

findLast

通过提供的函数返回值为真值(truthy)过滤数组,返回这个数组最后一个元素。

使用 Array.prototype.filter() 过滤掉 fn 返回假值(falsy)的元素, 用 Array.prototype.pop() 获取最后一个值。

const findLast = (arr, fn) => arr.filter(fn).pop();
findLast([1, 2, 3, 4], n => n % 2 === 1); // 3

findLastIndex

通过提供的函数返回值为真值(truthy)过滤数组,返回这个数组最后一个元素的下标。

使用 array.prototype.map() 将每个元素映射到具有其索引和值的数组。 使用 Array.prototype.filter() 过滤掉 fn 返回假值(falsy)的元素, 用 Array.prototype.pop() 获取最后一个值。

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

flatten

将数组展平到指定的深度。

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

const flatten = (arr, depth = 1) =>
  arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : 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.prototype.slice(0) 克隆给定的数组,Array.prototype.reverse() 反转数组,Array.prototype.forEach() 遍历这个反转的数组。

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

groupBy

根据给定的函数对数组的元素进行分组。

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

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

返回数组的第一个元素。

使用 arr[0] 返回传递数组的第一个元素。

const head = arr => arr[0];
head([1, 2, 3]); // 1

indexOfAll

返回数组中 val 的所有索引。如果在数组中没找到 val,则返回 []

使用 Array.prototype.reduce() 循环元素并存储匹配元素的索引。 返回索引数组。

const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
indexOfAll([1, 2, 3], 4); // []

initial

返回数组中除最后一个元素外的所有元素。

使用 arr.slice(0,-1) 返回数组中除最后一个元素外的所有元素。

const initial = arr => arr.slice(0, -1);
initial([1, 2, 3]); // [1,2]

initialize2DArray

初始化一个给定行数和列数,以及值的二维数组。

使用 array.prototype.map() 生成 h 行,其中每一行都是长度为 w 的新数组。如果没有提供值 val,则默认为 null

const initialize2DArray = (w, h, val = null) =>
  Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
initialize2DArray(2, 2, 0); // [[0,0], [0,0]]

initializeArrayWithRange

初始化一个数组,该数组包含指定范围 startend 内的数字,可设置间隔 step

使用 Array.from() 创建一个所需长度为 (end - start + 1)/step 的数组,并填充给定范围内要求的值。 你可以省略 start 来使用默认值 0。 你可以省略 step 使用默认值 1

const initializeArrayWithRange = (end, start = 0, step = 1) =>
  Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start);
initializeArrayWithRange(5); // [0,1,2,3,4,5]
initializeArrayWithRange(7, 3); // [3,4,5,6,7]
initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8]

initializeArrayWithRangeRight

[待翻译]

初始化一个数组,该数组包含指定范围 startend 内的数字(反向),可设置间隔 step

使用 array.from(Math.ceil((end+1-start)/step) 来创建所需长度的数组(元素的数量等于 (end-start)/step(end+1-start)/step ,包含结束数字), 使用 array.prototype.map() 来填充范围中所需要的值。

const initializeArrayWithRangeRight = (end, start = 0, step = 1) =>
  Array.from({ length: Math.ceil((end + 1 - start) / step) }).map(
    (v, i, arr) => (arr.length - i - 1) * step + start
  );
initializeArrayWithRangeRight(5); // [5,4,3,2,1,0]
initializeArrayWithRangeRight(7, 3); // [7,6,5,4,3]
initializeArrayWithRangeRight(9, 0, 2); // [8,6,4,2,0]

initializeArrayWithValues

使用指定的值初始化和填充数组。

使用 Array(n) 创建所需长度的数组,使用 fill(v) 填充所需的值。 你可以忽略 val ,使用默认值 0

const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
initializeArrayWithValues(5, 2); // [2, 2, 2, 2, 2]

initializeNDArray

创建一个具有给定值的 n 维数组。

使用递归。 使用 array.prototype.map() 生成行,其中每个行都是使用 initializeNDArray 初始化的新数组。

const initializeNDArray = (val, ...args) =>
  args.length === 0
    ? val
    : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
initializeNDArray(1, 3); // [1,1,1]
initializeNDArray(5, 2, 2, 2); // [[[5,5],[5,5]],[[5,5],[5,5]]]

intersection

返回两个数组中都存在的元素列表。

根据数组 b 创建一个 Set 对象,然后在数组 a 上使用 Array.prototype.filter() 方法,只保留数组 b 中也包含的值。

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

intersectionBy

将提供的函数应用于两个数组的每个数组元素后,返回两个数组中存在的元素列表。

fn 应用于 b 中的所有元素来创建 Set 对象 ,然后在 a 上使用 Array.prototype.filter(),只保留调用 fn 应用于每个元素后,同时在 b 中存在的元素。

const intersectionBy = (a, b, fn) => {
  const s = new Set(b.map(fn));
  return a.filter(x => s.has(fn(x)));
};
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1]

intersectionWith

使用提供的比较器(comparator)函数,返回两个数组中存在的元素列表。

使用 Array.prototype.filter()Array.prototype.findIndex() 结合比较器(comparator)函数来确定交叉值。

const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
intersectionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1.5, 3, 0]

isSorted

如果数组按升序排序,返回 1 ;如果按降序排序,返回 -1 ;如果没有排序,返回 0

计算前两个元素的顺序 direction。 使用 Object.entries() 对数组对象进行循环并对它们进行比较。 如果 direction 改变了,返回 0;如果循环直到最后一个元素,direction 没有改变,则返回 direction

const isSorted = arr => {
  let direction = -(arr[0] - arr[1]);
  for (let [i, val] of arr.entries()) {
    direction = !direction ? -(arr[i - 1] - arr[i]) : direction;
    if (i === arr.length - 1) return !direction ? 0 : direction;
    else if ((val - arr[i + 1]) * direction > 0) return 0;
  }
};
isSorted([0, 1, 2, 2]); // 1
isSorted([4, 3, 2]); // -1
isSorted([4, 3, 5]); // 0

join

将数组的所有元素拼接成一个字符串并返回此字符串。 使用分隔符和结束分隔符。

使用 Array.prototype.reduce() 将元素拼接成一个字符串。 省略第二个参数 separator ,则默认使用分隔符','。 省略第三个参数 end ,默认使用与 separator 相同的值。

const join = (arr, separator = ',', end = separator) =>
  arr.reduce(
    (acc, val, i) =>
      i === arr.length - 2
        ? acc + val + end
        : i === arr.length - 1
          ? acc + val
          : acc + val + separator,
    ''
  );
join(['pen', 'pineapple', 'apple', 'pen'], ',', '&'); // "pen,pineapple,apple&pen"
join(['pen', 'pineapple', 'apple', 'pen'], ','); // "pen,pineapple,apple,pen"
join(['pen', 'pineapple', 'apple', 'pen']); // "pen,pineapple,apple,pen"

JSONtoCSV

将对象数组转换为仅包含指定的 columns 的逗号分隔值(CSV)字符串。

使用 Array.prototype.join(delimiter) 结合 columns 中的所有名称以创建第一行。 使用 Array.prototype.map()Array.prototype.reduce() 为每个对象创建一行映射到 columns 中的值,用空字符串替换不存在的值。 使用 Array.prototype.join('\n') 将所有行组合成一个字符串。 省略第三个参数 delimiter ,使用 , 为默认的分隔符。

const JSONtoCSV = (arr, columns, delimiter = ',') =>
  [
    columns.join(delimiter),
    ...arr.map(obj =>
      columns.reduce(
        (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`,
        ''
      )
    )
  ].join('\n');
JSONtoCSV([{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], ['a', 'b']); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"'
JSONtoCSV([{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], ['a', 'b'], ';'); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"'

last

返回数组中的最后一个元素。

使用 arr.length - 1 来计算给定数组的最后一个元素的索引并返回。

const last = arr => arr[arr.length - 1];
last([1, 2, 3]); // 3

longestItem

获取任何数量的可迭代对象或具有 length 属性的对象,并返回其中长度最长的一个。 如果多个对象具有相同的长度,则返回第一个对象。 如果没有提供参数,则返回 undefined

使用 Array.prototype.reduce() ,比较对象的 length 以找到长度最长的对象。

const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a));
longestItem('this', 'is', 'a', 'testcase'); // 'testcase'
longestItem(...['a', 'ab', 'abc']); // 'abc'
longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd'
longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5]
longestItem([1, 2, 3], 'foobar'); // 'foobar'

mapObject

使用一个函数将数组的值映射到对象,在键值对中,原始值作为键,映射值作为值。

使用一个匿名的内部函数作用域来声明一个 undefined 的内存空间,使用闭包来存储返回值。 使用一个新的 Array 来存储带有函数映射的数组和一个逗号运算符来返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。

const mapObject = (arr, fn) =>
  (a => (
    (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
  ))();
const squareIt = arr => mapObject(arr, a => a * a);
squareIt([1, 2, 3]); // { 1: 1, 2: 4, 3: 9 }

maxN

从提供的数组中返回 n 个最大值元素。 如果 n 大于或等于提供的数组长度,则返回原始数组(按降序排列)。

使用 array.prototype.sort() 和 展开操作符 (...) 对数组进行浅克隆,并按降序排序。 使用 Array.prototype.slice() 获取指定数量的元素。 省略第二个参数 n ,获得只有一个元素的数组。

const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
maxN([1, 2, 3]); // [3]
maxN([1, 2, 3], 2); // [3,2]

minN

从提供的数组中返回 n 个最小值元素。 如果 n 大于或等于提供的数组长度,则返回原始数组(按升序排列)。

使用 array.prototype.sort() 和 展开操作符 (...) 对数组进行浅克隆,并按升序排序。 使用 Array.prototype.slice() 获取指定数量的元素。 省略第二个参数 n ,获得只有一个元素的数组。

const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
minN([1, 2, 3]); // [1]
minN([1, 2, 3], 2); // [1,2]

none

如果提供的断言(predicate)函数处理集合中的所有元素都返回 false ,则返回 true ,否则返回 false

使用 Array.prototype.some() 测试集合中的任何元素是否基于 fn 返回 true 。 省略第二个参数 fn ,使用 Boolean 作为默认值。

const none = (arr, fn = Boolean) => !arr.some(fn);
none([0, 1, 3, 0], x => x == 2); // true
none([0, 0, 0]); // true

nthElement

返回数组的第 n 个元素。

使用 array .prototype.slice() 首先获得一个包含第 n 个元素的数组。 如果索引超出界限,返回 undefined 。 省略第二个参数 n ,获得数组的第一个元素。

const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];
nthElement(['a', 'b', 'c'], 1); // 'b'
nthElement(['a', 'b', 'b'], -3); // 'a'

推荐资源- ES6:正确的部分

学习新的ES6 JavaScript语言特性,如箭头函数,解构,生成器和更多的编写更干净,更有效,可读的程序。

offset

将指定数量的元素移动到数组的末尾。

两次使用 Array.prototype.slice() 来获取指定索引之后的元素和指定索引之前的元素。 使用展开操作符(...)将两个数组合成一个数组。 如果 offset 为负数,元素将从结束移动到开始位置。

const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
offset([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2]
offset([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3]

partition

根据提供的函数对每个元素进行迭代,将元素分组为两个数组。

使用 array.prototype.reduce() 创建一个由两个数组组成的数组。 使用 array.prototype.push()fn 返回 true 的元素添加到第一个数组,而 fn 返回 false 的元素添加到第二个数组。

const partition = (arr, fn) =>
  arr.reduce(
    (acc, val, i, arr) => {
      acc[fn(val, i, arr) ? 0 : 1].push(val);
      return acc;
    },
    [[], []]
  );
const users = [{ user: 'barney', age: 36, active: false }, { user: 'fred', age: 40, active: true }];
partition(users, o => o.active); // [[{ 'user': 'fred',    'age': 40, 'active': true }],[{ 'user': 'barney',  'age': 36, 'active': false }]]

permutations

⚠️ WARNING: This function's execution time increases exponentially with each array element. Anything more than 8 to 10 entries will cause your browser to hang as it tries to solve all the different combinations.

Generates all permutations of an array's elements (contains duplicates).

Use recursion. For each element in the given array, create all the partial permutations for the rest of its elements. Use Array.prototype.map() to combine the element with each partial permutation, then Array.prototype.reduce() to combine all permutations in one array. Base cases are for array length equal to 2 or 1.

const permutations = arr => {
  if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr;
  return arr.reduce(
    (acc, item, i) =>
      acc.concat(
        permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val])
      ),
    []
  );
};
permutations([1, 33, 5]); // [ [ 1, 33, 5 ], [ 1, 5, 33 ], [ 33, 1, 5 ], [ 33, 5, 1 ], [ 5, 1, 33 ], [ 5, 33, 1 ] ]

pull

改变原始数组,过滤掉指定的值。

使用 Array.prototype.filter()array.prototype.include() 过滤指定的值。 使用 Array.prototype.length = 0 通过将数组的长度重置为0来清空数组,并使用 array.prototype.push() 把提取的值重新填充数组。

(对于不改变原始数组的代码片段,请参阅 without)

const pull = (arr, ...args) => {
  let argState = Array.isArray(args[0]) ? args[0] : args;
  let pulled = arr.filter((v, i) => !argState.includes(v));
  arr.length = 0;
  pulled.forEach(v => arr.push(v));
};
let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ]

pullAtIndex

改变原始数组,过滤掉指定索引的值。

使用 Array.prototype.filter()array.prototype.include() 过滤指定的值。 使用 Array.prototype.length = 0 通过将数组的长度重置为0来清空数组,并使用 array.prototype.push() 把提取的值重新填充数组。 使用 Array.prototype.push() 跟踪提取的值。

const pullAtIndex = (arr, pullArr) => {
  let removed = [];
  let pulled = arr
    .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
    .filter((v, i) => !pullArr.includes(i));
  arr.length = 0;
  pulled.forEach(v => arr.push(v));
  return removed;
};
let myArray = ['a', 'b', 'c', 'd'];
let pulled = pullAtIndex(myArray, [1, 3]); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]

pullAtValue

修改原始数组,过滤掉指定的值。返回删除的元素。

使用 Array.prototype.filter()array.prototype.include() 过滤指定的值。 使用 Array.prototype.length = 0 通过将数组的长度重置为0来清空数组,并使用 array.prototype.push() 把提取的值重新填充数组。 使用 Array.prototype.push() 跟踪提取的值。

const pullAtValue = (arr, pullArr) => {
  let removed = [],
    pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)),
    mutateTo = arr.filter((v, i) => !pullArr.includes(v));
  arr.length = 0;
  mutateTo.forEach(v => arr.push(v));
  return removed;
};
let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
let pulled = pullAtValue(myArray, ['b', 'd']); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]

pullBy

根据给定的迭代器(iterator)函数,修改原始数组,过滤掉指定的值。

检查函数中是否提供了最后一个参数。 使用 array.prototype.map() 将迭代器函数 fn 应用于所有数组元素。 使用 Array.prototype.filter()array.prototype.include() 过滤指定的值。 使用 Array.prototype.length = 0 通过将数组的长度重置为0来清空数组,并使用 array.prototype.push() 把提取的值重新填充数组。

const pullBy = (arr, ...args) => {
  const length = args.length;
  let fn = length > 1 ? args[length - 1] : undefined;
  fn = typeof fn == 'function' ? (args.pop(), fn) : undefined;
  let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val));
  let pulled = arr.filter((v, i) => !argState.includes(fn(v)));
  arr.length = 0;
  pulled.forEach(v => arr.push(v));
};
var myArray = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];
pullBy(myArray, [{ x: 1 }, { x: 3 }], o => o.x); // myArray = [{ x: 2 }]

reducedFilter

根据条件过滤一个对象数组,同时过滤掉未指定的键。

使用 array.prototype.filter() 根据断言函数 fn 对数组进行过滤,返回条件为真值(truthy)的对象。 在经过过滤后的数组上,使用 array.prototype.map()array.prototype.reduce() 过滤掉在 keys 参数中未提供的键。

const reducedFilter = (data, keys, fn) =>
  data.filter(fn).map(el =>
    keys.reduce((acc, key) => {
      acc[key] = el[key];
      return acc;
    }, {})
  );
const data = [
  {
    id: 1,
    name: 'john',
    age: 24
  },
  {
    id: 2,
    name: 'mike',
    age: 50
  }
];

reducedFilter(data, ['id', 'name'], item => item.age > 24); // [{ id: 2, name: 'mike'}]

reduceSuccessive

【待翻译】

对数组中的每个元素(从左到右)都应用累加器(accumulator)函数,返回依次减少一个值的数组。

使用 array.prototype.reduce() 将给定函数应用于给定数组,存储每个得到的新结果。

const reduceSuccessive = (arr, fn, acc) =>
  arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]);
reduceSuccessive([1, 2, 3, 4, 5, 6], (acc, val) => acc + val, 0); // [0, 1, 3, 6, 10, 15, 21]

reduceWhich

将提供的函数设置比较规则后应用于数组,返回数组的最小/最大值。

使用 array.prototype.reduce() 结合 comparator 函数来获取数组中合适的元素。 您可以省略第二个参数 comparator ,默认返回数组中最小的元素。

const reduceWhich = (arr, comparator = (a, b) => a - b) =>
  arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a));
reduceWhich([1, 3, 2]); // 1
reduceWhich([1, 3, 2], (a, b) => b - a); // 3
reduceWhich(
  [{ name: 'Tom', age: 12 }, { name: 'Jack', age: 18 }, { name: 'Lucy', age: 9 }],
  (a, b) => a.age - b.age
); // {name: "Lucy", age: 9}

reject

注:过滤掉符合断言函数条件的值

接受断言函数和数组,使用 array .prototype.filter() ,但仅当 pred(x) === false 时才保留 x

const reject = (pred, array) => array.filter((...args) => !pred(...args));
reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5]
reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi']

remove

从数组中移除给定函数返回 false 的元素。

使用 Array.prototype.filter()Array.prototype.reduce() 来查找数组中返回真值的元素,使用 Array.prototype.splice() 来移除元素。 func 有三个参数 (value, index, array)。

const remove = (arr, func) =>
  Array.isArray(arr)
    ? arr.filter(func).reduce((acc, val) => {
      arr.splice(arr.indexOf(val), 1);
      return acc.concat(val);
    }, [])
    : [];
remove([1, 2, 3, 4], n => n % 2 === 0); // [2, 4]

sample

从数组中返回一个随机元素。

使用 Math.random() 生成随机数,将其乘以 length ,并使用 Math.floor() 将其四舍五入到最近的整数。 这个方法也适用于字符串。

const sample = arr => arr[Math.floor(Math.random() * arr.length)];
sample([3, 7, 9, 11]); // 9

sampleSize

array 中获取 n 个唯一键随机元素。

使用 Fisher-Yates algorithm算法 对数组进行打乱。 使用Array.prototype.slice() 获取 n 个元素。 省略第二个参数 n, 从数组中随机获取 1 个元素。

const sampleSize = ([...arr], n = 1) => {
  let m = arr.length;
  while (m) {
    const i = Math.floor(Math.random() * m--);
    [arr[m], arr[i]] = [arr[i], arr[m]];
  }
  return arr.slice(0, n);
};
sampleSize([1, 2, 3], 2); // [3,1]
sampleSize([1, 2, 3], 4); // [2,3,1]

shank

具有与Array.prototype.splice()相同的功能,但是 Array.prototype.splice() 返回一个新数组,而不是修改原始数组。

在删除现有元素 和/或 添加新元素之后,使用 array.prototype.slice()array.prototype.concat() 获得一个包含新内容的新数组。 省略第二个参数 index ,下标从 0 开始。 省略第三个参数 delCount ,删除 0 个元素。 省略第四个参数 elements ,不添加任何新元素。

const shank = (arr, index = 0, delCount = 0, ...elements) =>
  arr
    .slice(0, index)
    .concat(elements)
    .concat(arr.slice(index + delCount));
const names = ['alpha', 'bravo', 'charlie'];
const namesAndDelta = shank(names, 1, 0, 'delta'); // [ 'alpha', 'delta', 'bravo', 'charlie' ]
const namesNoBravo = shank(names, 1, 1); // [ 'alpha', 'charlie' ]
console.log(names); // ['alpha', 'bravo', 'charlie']

shuffle

随机排列指定数组元素的顺序,返回一个新的数组。

使用 Fisher-Yates algorithm 算法 对数组元素进行重新排序。

const shuffle = ([...arr]) => {
  let m = arr.length;
  while (m) {
    const i = Math.floor(Math.random() * m--);
    [arr[m], arr[i]] = [arr[i], arr[m]];
  }
  return arr;
};
const foo = [1, 2, 3];
shuffle(foo); // [2, 3, 1], foo = [1, 2, 3]

similarity

返回两个数组的交集。

使用 Array.prototype.filter() 移除不属于 values 中的值,这些值由 array .prototype.include() 来确定。

const similarity = (arr, values) => arr.filter(v => values.includes(v));
similarity([1, 2, 3], [1, 2, 4]); // [1, 2]

sortedIndex

返回指定值插入到数组中的最小索引位置,以保持其排序顺序。

检查数组是否按降序(松散地)排序。 使用 Array.prototype.findIndex() 找到元素应该被插入的合适的索引位置。

const sortedIndex = (arr, n) => {
  const isDescending = arr[0] > arr[arr.length - 1];
  const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));
  return index === -1 ? arr.length : index;
};
sortedIndex([5, 3, 2, 1], 4); // 1
sortedIndex([30, 50], 40); // 1

sortedIndexBy

返回根据提供的迭代器函数,将指定值插入到数组中的最小索引位置,以保持其排序顺序。

检查数组是否按降序(松散地)排序。 使用 Array.prototype.findIndex() 根据迭代器函数 fn 查找应该插入元素的适当索引。

const sortedIndexBy = (arr, n, fn) => {
  const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
  const val = fn(n);
  const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
  return index === -1 ? arr.length : index;
};
sortedIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 0

sortedLastIndex

返回指定值插入到数组中的最大索引位置,以保持其排序顺序。

检查数组是否按降序(松散地)排序。 使用 Array.prototype.reverse()Array.prototype.findIndex() 查找应该插入元素的最后一个适当的索引。

const sortedLastIndex = (arr, n) => {
  const isDescending = arr[0] > arr[arr.length - 1];
  const index = arr.reverse().findIndex(el => (isDescending ? n <= el : n >= el));
  return index === -1 ? 0 : arr.length - index;
};
sortedLastIndex([10, 20, 30, 30, 40], 30); // 4

sortedLastIndexBy

返回根据提供的迭代器函数,将指定值插入到数组中的最大索引位置,以保持其排序顺序。

检查数组是否按降序(松散地)排序。 使用 array.prototype.map() 将迭代器函数应用于数组的所有元素。 使用 Array.prototype.reverse()Array.prototype.findIndex() 根据提供的迭代器函数,查找应该插入元素的最后一个适当的索引。

const sortedLastIndexBy = (arr, n, fn) => {
  const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
  const val = fn(n);
  const index = arr
    .map(fn)
    .reverse()
    .findIndex(el => (isDescending ? val <= el : val >= el));
  return index === -1 ? 0 : arr.length - index;
};
sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 1

stableSort

对数组执行稳定排序,值相同时保留其初始索引。 不改变原始数组,而是返回新数组。

使用 array.prototype.map() 将输入数组的每个元素与其对应的索引配对。 使用 Array.prototype.sort()compare 函数对列表进行排序,如果比较的值相等,则保留它们的初始顺序。 使用 array.prototype.map() 将其转换回初始数组项。

const stableSort = (arr, compare) =>
  arr
    .map((item, index) => ({ item, index }))
    .sort((a, b) => compare(a.item, b.item) || a.index - b.index)
    .map(({ item }) => item);
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const stable = stableSort(arr, () => 0); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

symmetricDifference

返回两个数组之间的差集,而不过滤重复的值。

根据每个数组创建一个 Set ,然后在每个数组上使用 array.prototype.filter() ,只保留不包含在另一个数组中的值。

const symmetricDifference = (a, b) => {
  const sA = new Set(a),
    sB = new Set(b);
  return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
};
symmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4]
symmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 2, 3]

symmetricDifferenceBy

将提供的函数应用于两个数组的每个元素后,返回两个数组之间的差集。

根据每个数组创建一个 Set ,然后在每个数组上使用 array.prototype.filter() ,只保留不包含在另一个数组中的值。

const symmetricDifferenceBy = (a, b, fn) => {
  const sA = new Set(a.map(v => fn(v))),
    sB = new Set(b.map(v => fn(v)));
  return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))];
};
symmetricDifferenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [ 1.2, 3.4 ]

symmetricDifferenceWith

使用提供的函数作为比较器,返回两个数组之间的差集。

使用 Array.prototype.filter()Array.prototype.findIndex() 查找合适的值。

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

tail

返回数组中除第一个元素外的所有元素。

如果数组的 length 大于 1, ,则返回 Array.prototype.slice(1),否则返回整个数组。

const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
tail([1, 2, 3]); // [2,3]
tail([1]); // [1]

take

返回从开头开始提取 n 个元素的数组。

使用 array.prototype.slice() 创建数组的一个切片,其中包含从开头开始提取的 n 个元素。

const take = (arr, n = 1) => arr.slice(0, n);
take([1, 2, 3], 5); // [1, 2, 3]
take([1, 2, 3], 0); // []

takeRight

返回从结尾开始向前提取 n 个元素的数组。

使用 array.prototype.slice() 创建数组的一个切片,其中包含从结尾开始向前提取的 n 个元素。

const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
takeRight([1, 2, 3], 2); // [ 2, 3 ]
takeRight([1, 2, 3]); // [3]

takeRightWhile

从数组末尾移除元素,直到传递的函数返回“true”。返回删除的元素。

const takeRightWhile = (arr, func) =>
  arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []);
takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4]

takeWhile

从数组的开头开始删除数组中的元素,直到传递的函数返回 true 。返回删除的元素。

循环遍历数组,使用 for...of 循环 Array.prototype.entries() 拿到的值, 直到函数返回的值为 true 为止。 使用 Array.prototype.slice() 返回删除的元素。

const takeWhile = (arr, func) => {
  for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i);
  return arr;
};
takeWhile([1, 2, 3, 4], n => n >= 3); // [1, 2]

toHash

将给定的类数组简化为值哈希(value hash)(有键的数据存储)。

给定一个可迭代的类数组结构,在提供的对象上调用 Array.prototype.reduce.call() 逐个处理元素,并返回一个对象,该对象由键引用一个值。

const toHash = (object, key) =>
  Array.prototype.reduce.call(
    object,
    (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc),
    {}
  );
toHash([4, 3, 2, 1]); // { 0: 4, 1: 3, 2: 2, 3: 1 }
toHash([{ a: 'label' }], 'a'); // { label: { a: 'label' } }
// A more in depth example:
let users = [{ id: 1, first: 'Jon' }, { id: 2, first: 'Joe' }, { id: 3, first: 'Moe' }];
let managers = [{ manager: 1, employees: [2, 3] }];
// We use function here because we want a bindable reference, but a closure referencing the hash would work, too.
managers.forEach(
  manager =>
    (manager.employees = manager.employees.map(function(id) {
      return this[id];
    }, toHash(users, 'id')))
);
managers; // [ { manager:1, employees: [ { id: 2, first: "Joe" }, { id: 3, first: "Moe" } ] } ]

union

返回两个数组的并集,相同的元素只出现一次。

基于 ab 创建一个 Set 对象,返回转换后的数组。

const union = (a, b) => Array.from(new Set([...a, ...b]));
union([1, 2, 3], [4, 3, 2]); // [1,2,3,4]

unionBy

将所提供的函数应用于两个数组的每个元素之后,返回两个数组的并集,相同的元素只出现一次。

fn 应用于 a 的所有元素后创建一个 Set,并在 b 中过滤已经在集合中存在的元素。 最后返回一个转换为数组的集合。

const unionBy = (a, b, fn) => {
  const s = new Set(a.map(fn));
  return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))]));
};
unionBy([2.1], [1.2, 2.3], Math.floor); // [2.1, 1.2]

unionWith

使用提供的比较器函数,返回两个数组的并集,相同的元素只出现一次。

Array.prototype.findIndex() 使用提供的比较器函数后,在 b 中查找没有在 a 中匹配的值。

const unionWith = (a, b, comp) =>
  Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));
unionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2, 1.5, 3, 0, 3.9]

uniqueElements

返回去重后的数组。

使用 ES6 的 Set...rest 运算符去除所有重复的值。

const uniqueElements = arr => [...new Set(arr)];
uniqueElements([1, 2, 2, 3, 4, 4, 5]); // [1, 2, 3, 4, 5]

uniqueElementsBy

根据提供的比较器函数,返回去重后的数组。

根据比较器函数 fn, 使用 Array.prototype.reduce()Array.prototype.some() 去除重复的值,只保留重复值中第一个出现的值。 比较器(comparator)函数接受两个参数:正在比较的两个元素的值。

const uniqueElementsBy = (arr, fn) =>
  arr.reduce((acc, v) => {
    if (!acc.some(x => fn(v, x))) acc.push(v);
    return acc;
  }, []);
uniqueElementsBy(
  [
    { id: 0, value: 'a' },
    { id: 1, value: 'b' },
    { id: 2, value: 'c' },
    { id: 1, value: 'd' },
    { id: 0, value: 'e' }
  ],
  (a, b) => a.id == b.id
); // [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ]

uniqueElementsByRight

根据提供的比较器函数,从右边开始,返回去重后的数组。

根据比较器函数 fn, 从右边开始,使用 Array.prototype.reduceRight()Array.prototype.some() 去除重复的值,只保留重复值中最后一个出现的值。 比较器(comparator)函数接受两个参数:正在比较的两个元素的值。

const uniqueElementsByRight = (arr, fn) =>
  arr.reduceRight((acc, v) => {
    if (!acc.some(x => fn(v, x))) acc.push(v);
    return acc;
  }, []);
uniqueElementsByRight(
  [
    { id: 0, value: 'a' },
    { id: 1, value: 'b' },
    { id: 2, value: 'c' },
    { id: 1, value: 'd' },
    { id: 0, value: 'e' }
  ],
  (a, b) => a.id == b.id
); // [ { id: 0, value: 'e' }, { id: 1, value: 'd' }, { id: 2, value: 'c' } ]

uniqueSymmetricDifference

返回两个数组的差集,在两个数组中不重复的值。

在每个数组上使用 array.prototype.filter()array .prototype.include() 来过滤另一个数组中包含的值,然后从结果中创建一个 Set ,删除重复的值。

const uniqueSymmetricDifference = (a, b) => [
  ...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))])
];
uniqueSymmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4]
uniqueSymmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 3]

unzip

创建一个数组,将 zip 生成的数组中的元素取消分组。

使用 Math.max.apply() 获取数组中最长子数组的长度,使用 Array.prototype.map() 生成最长长度个数组。 使用 Array.prototype.reduce()Array.prototype.forEach() 将分组元素映射到对应的数组中。

const unzip = arr =>
  arr.reduce(
    (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
    Array.from({
      length: Math.max(...arr.map(x => x.length))
    }).map(x => [])
  );
unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]]
unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]]

unzipWith

创建一个数组,将 zip 生成的数组中的元素取消分组,并结合提供的函数生成最后的结果。

使用 Math.max.apply() 获取数组中最长子数组的长度,使用 Array.prototype.map() 生成最长长度个数组。 使用 Array.prototype.reduce()Array.prototype.forEach() 将分组元素映射到对应的数组中。 使用 Array.prototype.map() 和展开操作符 (...) 将 fn 应用于每一组元素。

const unzipWith = (arr, fn) =>
  arr
    .reduce(
      (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
      Array.from({
        length: Math.max(...arr.map(x => x.length))
      }).map(x => [])
    )
    .map(val => fn(...val));
unzipWith([[1, 10, 100], [2, 20, 200]], (...args) => args.reduce((acc, v) => acc + v, 0)); // [3, 30, 300]

without

过滤掉数组中具有指定值之一的元素。

使用 array.prototype.filter() 创建一个数组,排除(使用 !array.include() )所有给定值。

(改变原始数组,请看 pull) 代码片段

const without = (arr, ...args) => arr.filter(v => !args.includes(v));
without([2, 1, 2, 3], 1, 2); // [3]

xProd

将两个数组的每个元素两两进行组合,组合出所有的可能对存在数组中,返回一个存在所有可能性对的数组。

使用 Array.prototype.reduce(), Array.prototype.map()Array.prototype.concat() 从两个数组的元素中生成所有可能的对,并将它们保存在一个数组中。

const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
xProd([1, 2], ['a', 'b']); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]

zip

创建一个根据原始数组中的位置进行分组的数组。

使用 Math.max.apply() 获取参数中最长的数组,创建一个长度为该长度的数组,并使用Array.from() 和映射函数(map-function) 来创建一个分组元素数组。 如果参数数组的长度不同,则在未找到值的情况下使用 undefined

const zip = (...arrays) => {
  const maxLength = Math.max(...arrays.map(x => x.length));
  return Array.from({ length: maxLength }).map((_, i) => {
    return Array.from({ length: arrays.length }, (_, k) => arrays[k][i]);
  });
};
zip(['a', 'b'], [1, 2], [true, false]); // [['a', 1, true], ['b', 2, false]]
zip(['a'], [1, 2], [true, false]); // [['a', 1, true], [undefined, 2, false]]

zipObject

给定一个有效属性标识符数组和一个值数组,返回一个将属性关联到值的对象。

由于对象可以有未定义的值,但不能有未定义的属性名,所以属性数组使用 array.prototype.reduce() 来决定结果对象的结构。

const zipObject = (props, values) =>
  props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {});
zipObject(['a', 'b', 'c'], [1, 2]); // {a: 1, b: 2, c: undefined}
zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2}

zipWith

创建一个根据原始数组中的位置进行分组的数组,并使用函数作为最后一个参数来指定应如何组合分组中的值。

检查最后提供的参数是否为函数。 使用 Math.max.apply() 获取参数中最长的数组,创建一个长度为该长度的数组,并使用Array.from() 和映射函数(map-function) 来创建一个分组元素数组。 如果参数数组的长度不同,则在找不到值的地方使用“undefined”。 最后一个参数提供的函数应用于每个组 (...group) 的元素。

const zipWith = (...array) => {
  const fn = typeof array[array.length - 1] === 'function' ? array.pop() : undefined;
  return Array.from(
    { length: Math.max(...array.map(a => a.length)) },
    (_, i) => (fn ? fn(...array.map(a => a[i])) : array.map(a => a[i]))
  );
};
zipWith([1, 2], [10, 20], [100, 200], (a, b, c) => a + b + c); // [111,222]
zipWith(
  [1, 2, 3],
  [10, 20],
  [100, 200],
  (a, b, c) => (a != null ? a : 'a') + (b != null ? b : 'b') + (c != null ? c : 'c')
); // [111, 222, '3bc']