ECMAScript 攻略

Array#{flat,flatMap}

ECMAScript 2019 在 Array.prototype 上增加了两个方法:flat()flatMap()

这两个方法为打平数组提供了便利。如果没有这两个方法,则打平数组就要使用迭代或递归

// 手写实现
/*
数组中每个元素都像一个子节点,非数组元素是叶节点。
因此,这个例子中的输入数组是一个高度为 2 有 7 个叶节点的树。打平这个数组本质上是对叶节点的按
序遍历。

第一个参数:源数组
第二个参数:指定打平到第几级嵌套
第三个参数:新数组

*/

function flatten(sourceArray, depth, flattenedArray = []) {
  for (const element of sourceArray) {
    if (Array.isArray(element) && depth > 0) {
      flatten(element, depth - 1, flattenedArray);
    } else {
      flattenedArray.push(element);
    }
  }
  return flattenedArray;
}

const arr = [[0], 1, 2, [3, [4, 5]], 6];

console.log(flatten(arr, 1));

// [0, 1, 2, 3, [4, 5], 6]

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

const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]

const arr2 = [0, 1, 2, [[[3, 4]]]];

console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]

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

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

典型场景: 将包含几句话的数组拆分成单个词组成的新数组

let arr1 = ["it's Sunny in", "", "California"];

arr1.map((x) => x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]

arr1.flatMap((x) => x.split(" "));
// ["it's","Sunny","in", "", "California"]

详细内容参考 ES 入门 - flat

Object.fromEntries

提出背景: 前端使用 Map 结构存储数据,但是调用后端 API 时需要传递普通对象,这时候就可以使用Object.fromEntries()进行转换

Object.fromEntries 是与 Object.entries() 相反的方法,用于将一个键值对数组转为对象。

Object.fromEntries([
  ["foo", "bar"],
  ["baz", 42],
]);
// { foo: "bar", baz: 42 }

该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。

使用场景:

Map 键值对结构转换为对象

// 例一
const entries = new Map([
  ["foo", "bar"],
  ["baz", 42],
]);

Object.fromEntries(entries);
// { foo: "bar", baz: 42 }

// 例二
const map = new Map().set("foo", true).set("bar", false);
Object.fromEntries(map);
// { foo: true, bar: false }

Array 转化为 Object

const arr = [
  ["0", "a"],
  ["1", "b"],
  ["2", "c"],
];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }

浏览器查询参数转换为对象

let query = Object.fromEntries(new URLSearchParams("foo=bar&baz=qux"));
// {foo: "bar", baz: "qux"}
console.log(query);

将对象的值重新组合

let arr = [
  { name: "Alice", age: 40 },
  { name: "Bob", age: 36 },
];
let obj = Object.fromEntries(arr.map(({ name, age }) => [name, age]));
// {Alice: 40, Bob: 36}
console.log(obj);

String#{trimStart,trimEnd}

ES2019 对字符串实例新增了trimStart()trimEnd()这两个方法。它们的行为与trim()一致,

  • trimStart()消除字符串头部的空格,
  • trimEnd()消除尾部的空格。

它们返回的都是新字符串,不会修改原始字符串。

const s = "  abc  ";

s.trim(); // "abc"
s.trimStart(); // "abc  "
s.trimEnd(); // "  abc"
复制代码

Symbol#description

创建 Symbol 的时候,可以添加一个描述。

const sym = Symbol("foo");

上面代码中,sym 的描述就是字符串 foo

但是,读取这个描述需要将 Symbol 显式转为字符串,即下面的写法。

const sym = Symbol("foo");

String(sym); // "Symbol(foo)"
sym.toString(); // "Symbol(foo)"

上面的用法不是很方便。ES2019 提供了一个实例属性 description,直接返回 Symbol 的描述。

const sym = Symbol("foo");

sym.description; // "foo"

ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。

// 创建 Symbol 的时候,可以添加一个描述。
const sym = Symbol("foo");

sym.description; // "foo"

上面代码中,sym 的描述就是字符串 foo

try {} catch {} // optional binding

旧版本的try / catch语句中的catch子句需要一个变量。 现在可以不加了

// 旧版本
try {
  console.log(a);
} catch (error) {
  console.log("报错了");
}

// ES2019-SE10

// 如果我们对错误信息漠不关心,只想知道是否报错,就可以忽略catch的参数
try {
  console.log(a);
  return true;
} catch {
  console.log("报错了");
  return false;
}

U+2028 和 U+2029

在 ES2019 之前的版本中,不接受不转义的

  • 行分隔符U + 2028
  • 段落分隔符U + 2029

ES2019 允许 JavaScript 字符串直接输入 U+2028(行分隔符)和 U+2029(段分隔符)。

/*
ES2019之前,下面的代码会报错

ES2019 下面代码不会报错。
*/
const PS = eval("'\u2029'");

ES 入门 - U+2028 和 U+2029

JSON-stringify - 的改造

为了确保返回的是合法的 UTF-8 字符,ES2019 改变了 JSON.stringify()的行为。如果遇到 0xD8000xDFFF 之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。

JSON.stringify("\u{D834}"); // ""\\uD834""
JSON.stringify("\uDF06\uD834"); // ""\\udf06\\ud834""

ES 入门 - JSON-stringify - 的改造

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

早先的 ECMAScript 没有规定,Array.prototype.sort()的默认排序算法是否稳定,留给浏览器自己决定,这导致某些实现是不稳定的。ES2019 明确规定,Array.prototype.sort()的默认排序算法必须稳定。这个规定已经做到了,现在 JavaScript 各个主要实现的默认排序算法都是稳定的。

const arr = ["peach", "straw", "apple", "spork"];

const stableSorting = (s1, s2) => {
  if (s1[0] < s2[0]) return -1;
  return 1;
};

arr.sort(stableSorting);
// ["apple", "peach", "straw", "spork"]

ES 入门 - 排序稳定性

revised Function#toString

ES2019 对函数实例的 toString()方法做出了修改。

toString()方法返回函数代码本身,以前会省略注释和空格。

function /* foo comment */ foo() {}

// 老版本
foo.toString();
// function foo() {}

// 新版
foo.toString();
// "function /* foo comment */ foo () {}"

Last Updated: