2021.04.27(数组实例的 includes()、数组实例的 flat(),flatMap()、数组的空位、Array.prototype.sort() 的排序稳定性)

数组实例的 includes()

Array.prototype.includes  方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串
的 includes  方法类似。ES2016 引入了该方法。

1.  [1, 2, 3].includes(2) // true
2.  [1, 2, 3].includes(4) // false
3.  [1, 2, NaN].includes(NaN) // true

该方法的第二个参数表示搜索的起始位置,默认为 0  。如果第二个参数为负数,则表示倒数的位置,
如果这时它大于数组长度(比如第二个参数为 -4  ,但数组长度为 3  ),则会重置为从 0  开始。

1.  [1, 2, 3].includes(3, 3); // false
2.  [1, 2, 3].includes(3, -1); // true

没有该方法之前,我们通常使用数组的 indexOf  方法,检查是否包含某个值。

1.  if (arr.indexOf(el) !== -1) {
2.  // ...
3.  }

indexOf  方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比
较是否不等于 -1  ,表达起来不够直观。二是,它内部使用严格相等运算符( ===  )进行判断,这
会导致对 NaN  的误判。

1.  [NaN].indexOf(NaN)
2.  // -1

includes  使用的是不一样的判断算法,就没有这个问题。

1.  [NaN].includes(NaN)
2.  // true

下面代码用来检查当前环境是否支持该方法,如果不支持,部署一个简易的替代版本。

1.  const contains = (() =>
2.  Array.prototype.includes
3.  ? (arr, value) => arr.includes(value)
4.  : (arr, value) => arr.some(el => el === value)
5.  )();
6.  contains(['foo', 'bar'], 'baz'); // => false

另外,Map 和 Set 数据结构有一个 has  方法,需要注意与 includes  区分。
Map 结构的 has  方法,是用来查找键名的,比
如 Map.prototype.has(key)  、 WeakMap.prototype.has(key)  、 Reflect.has(target,
propertyKey)  。
Set 结构的 has  方法,是用来查找值的,比
如 Set.prototype.has(value)  、 WeakSet.prototype.has(value)  。

数组实例的 flat(),flatMap()

数组的成员有时还是数组, Array.prototype.flat()  用于将嵌套的数组“拉平”,变成一维的数
组。该方法返回一个新数组,对原数据没有影响。

1.  [1, 2, [3, 4]].flat()
2.  // [1, 2, 3, 4]

上面代码中,原数组的成员里面有一个数组, flat()  方法将子数组的成员取出来,添加在原来的位
置。

flat()  默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将 flat()  方法的参数写成
一个整数,表示想要拉平的层数,默认为1。

1.  [1, 2, [3, [4, 5]]].flat()
2.  // [1, 2, 3, [4, 5]]
3.
4.  [1, 2, [3, [4, 5]]].flat(2)
5.  // [1, 2, 3, 4, 5]

上面代码中, flat()  的参数为2,表示要“拉平”两层的嵌套数组。
如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity  关键字作为参数。

1.  [1, [2, [3]]].flat(Infinity)
2.  // [1, 2, 3]

如果原数组有空位, flat()  方法会跳过空位。

1.  [1, 2, , 4, 5].flat()
2.  // [1, 2, 4, 5]

flatMap()  方法对原数组的每个成员执行一个函数(相当于执行 Array.prototype.map()  ),然
后对返回值组成的数组执行 flat()  方法。该方法返回一个新数组,不改变原数组。

1.  // 相当于 [[2, 4], [3, 6], [4, 8]].flat()
2.  [2, 3, 4].flatMap((x) => [x, x * 2])
3.  // [2, 4, 3, 6, 4, 8]

flatMap()  只能展开一层数组。

1.  // 相当于 [[[2]], [[4]], [[6]], [[8]]].flat()
2.  [1, 2, 3, 4].flatMap(x => [[x * 2]])
3.  // [[2], [4], [6], [8]]

上面代码中,遍历函数返回的是一个双层的数组,但是默认只能展开一层,因此 flatMap()  返回的
还是一个嵌套数组。
flatMap()  方法的参数是一个遍历函数,该函数可以接受三个参数,分别是当前数组成员、当前数
组成员的位置(从零开始)、原数组。

1.  arr.flatMap(function callback(currentValue[, index[, array]]) {
2.  // ...
3.  }[, thisArg])

flatMap()  方法还可以有第二个参数,用来绑定遍历函数里面的 this  。

数组的空位

数组的空位指,数组的某一个位置没有任何值。比如, Array  构造函数返回的数组都是空位。

1.  Array(3) // [, , ,]

上面代码中, Array(3)  返回一个具有 3 个空位的数组。
注意,空位不是 undefined  ,一个位置的值等于 undefined  ,依然是有值的。空位是没有任何
值, in  运算符可以说明这一点。

1.  0 in [undefined, undefined, undefined] // true
2.  0 in [, , ,] // false

ES6 则是明确将空位转为 undefined  。

Array.prototype.sort() 的排序稳定性

排序稳定性(stable sorting)是排序算法的重要属性,指的是排序关键字相同的项目,排序前后的
顺序不变。

1.  const arr = [
2.  'peach',
3.  'straw',
4.  'apple',
5.  'spork'
6.  ];
7.
8.  const stableSorting = (s1, s2) => {
9.  if (s1[0] < s2[0]) return -1;
10.  return 1;
11.  };
12.
13.  arr.sort(stableSorting)
14.  // ["apple", "peach", "straw", "spork"]

上面代码对数组 arr  按照首字母进行排序。排序结果中, straw  在 spork  的前面,跟原始顺序
一致,所以排序算法 stableSorting  是稳定排序。

1.  const unstableSorting = (s1, s2) => {
2.  if (s1[0] <= s2[0]) return -1;
3.  return 1;
4.  };
5.
6.  arr.sort(unstableSorting)
7.  // ["apple", "peach", "spork", "straw"]

上面代码中,排序结果是 spork  在 straw  前面,跟原始顺序相反,所以排序算
法 unstableSorting  是不稳定的。

ES2019 明确规定, Array.prototype.sort()  的默认
排序算法必须稳定。这个规定已经做到了,现在 JavaScript 各个主要实现的默认排序算法都是稳定
的。

 

2021-04-27  14:21:07

posted @ 2021-04-27 14:21  铁打的代码流水的bug  阅读(96)  评论(0)    收藏  举报