ECMAScript 2020 中新功能罗列

本贴最后更新于 1700 天前,其中的信息可能已经时异事殊

ECMAScript 2020 中有哪些新功能?

驱动 JavaScript 的语言规范称为 ECMAScript,这个帖子也是分享一些和探讨 ES2020 之下的最新规范,对前端感兴趣的朋友可以关注关注。

由于许多人的电脑是不更新浏览器的,这也是很多前端开发头疼的地方,很多新的规范和方法并不能直接使用!如果需要简化开发人员的生活,我们需要使用 babel 来开始使用用户无法全面使用的功能。

 yarn add parcel-bundler
"scripts": {
  "start": "parcel index.html"
},

.babelrc 配置

{
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator",
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-private-methods",
    "@babel/plugin-syntax-bigint"
  ]
}

备注:下面的例子我都是通过 chrome80+ 运行的

flat & flatMap

image.png

Array.prototype.flat()计划将数组递归展平至所需深度,并返回替换数组

语法:Array.prototype.flat(depth)
depth —默认值为1,使用时间展平所有嵌套的数组。
const numbers = [1, 2, [3, 4, [5, 6]]];
// Considers default depth of 1
numbers.flat(); 
> [1, 2, 3, 4, [5, 6]]
// With depth of 2
numbers.flat(2); 
> [1, 2, 3, 4, 5, 6]
// Executes two flat operations
numbers.flat().flat(); 
> [1, 2, 3, 4, 5, 6]
// Flattens recursively until the array contains no nested arrays
numbers.flat(Infinity)
> [1, 2, 3, 4, 5, 6]

Array.prototype.flatMap()映射使用映射执行的每个部分,并将结果展平为替换数组。它是地图操作的副本,后跟一个 depth = 1

语法:Array.prototype.flatMap(callback)
回调:执行该操作将产生新Array的一部分
const numbers = [1, 2, 3];
numbers.map(x => [x * 2]);
> [[2], [4], [6]]
numbers.flatMap(x => [x * 2]);
> [2, 4, 6]

私有类变量

类的主要目的之一是将我们的代码包含在可重用的模块中。一个类会在许多不同地方使用,但是又不希望类中的变量都是 public,目前 JS 并不支持私有变量。

现在,通过在变量或函数前面添加一个简单的哈希符号,就可以实现私有变量了,也算是语法糖吧

class Message {
  #message = "Howdy"

  greet() { console.log(this.#message) }
}

const greeting = new Message()

greeting.greet() // Howdy
console.log(greeting.#message) // Private name #message is not defined

Object.fromEntries

Object.fromEntries 执行与 Object.entries 相反的操作。它将键值对列表转换为 AN 对象。

语法:Object.fromEntries(iterable)
iterable:类似于Array或Map的可迭代对象,或实现可迭代协议的对象
const records = [['name','Mathew'], ['age', 32]];
const obj = Object.fromEntries(records);
> { name: 'Mathew', age: 32}
Object.entries(obj);
> [['name','Mathew'], ['age', 32]];

<strong>Promise.allSettled()</strong> 方法返回一个在所有给定的 promise 已被决议或被拒绝后决议的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// expected output:
// "fulfilled"
// "rejected"

大整数(BigInt)

image.png

由于 JavaScript 处理数字的方式,当您提高数字时,事情会变得有些古怪。如果大家在处理一些小数比较多的图表计算,很容易踩 JS 处理数字的方式的坑。

JavaScript 可以处理的最大数字是 2 ^ 53,可以通过 MAX_SAFE_INTEGER 查看

const max = Number.MAX_SAFE_INTEGER;

console.log(max); // 9007199254740991

下面是一些 ❎ 和奇怪的 JS 计算方式

console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992
console.log(max + 3); // 9007199254740994
console.log(Math.pow(2, 53) == Math.pow(2, 53) + 1); // true

这时候就可以使用新的 BigInt 数据类型解决此问题。在数字末尾加上字母'n',我们可以开始使用并与大量数字互动。

备注:无法将标准数字与 BigInt 数字混合使用,因此任何数学运算都需要使用 BigInts 完成

const bigNum = 100000000000000000000000000000n;

console.log(bigNum * 2n); // 200000000000000000000000000000n

String.prototype.trimStart() & trimEnd()

这是我最爱的方法之一

trimStart() 从字符串的开头删除空格,trimEnd() 从字符串的开头删除空格。

const greeting = ` Hello Javascript! `;
greeting.length;
> 19
greeting = greeting.trimStart();
> 'Hello Javascript! '
greeting.length;
> 18
greeting = 'Hello World!   ';
greeting.length;
> 15
greeting = greeting.trimEnd();
> 'Hello World!'
greeting.length;
> 12

Nullish Coalescing Operator

这个不好翻译,可以理解为更为严格的 || 运算符

由于 JavaScript 是动态类型的,因此在分配变量时,您需要牢记 JavaScript 对真实/错误值的处理。但是 JS 对于空字符串和 || 处理很奇怪。比如我们需要判断一个对象属性是否存在,不存在则为其他值:

let a = {a:0}
let b = {}
b.a = a.a || 1
> b.a = 1

这明显是不对的,目的是将 b.a 设置为 a.a 的值,仅因为 a.a = 0,导致表达式运行结果不同,这在前端开发中是很隐晦很隐晦的 bug,一不小心就会犯错,比如我,经常采坑。

代替双管道 ||,我们可以使用双问号运算符将类型更严格一些( ?? ),仅当值为 null undefined 时才允许使用默认值。

let person = {
  profile: {
    name: "",
    age: 0
  }
};
console.log(person.profile.name ?? "Anonymous"); // ""
console.log(person.profile.age ?? 18); // 0

Optional Chaining Operator

这个 babel 工具如果大家关注一些前端信息的话,会听得比较多,也是受到好评的,虽然写起来的代码看起来并不是那么优雅。

如果我们想要的是未定义的,我们可以返回一个值,但是如果它的路径是未定义的,该怎么办?这时候就体现了 Optional Chaining Operator 的作用了

let person = {};

console.log(person.profile.name ?? "Anonymous"); // person.profile is undefined
console.log(person?.profile?.name ?? "Anonymous"); // 在. 之前加上问号?
console.log(person?.profile?.age ?? 18);

动态导入

如果你在开发中写了一个充满实用程序功能的文件(util.js),其中某些功能可能很少使用,而导入其所有依赖项可能只是浪费资源。现在,我们可以使用 async / await 在需要时动态导入依赖项。

这个不适用于浏览器,仅仅适用于 Node.js 环境

const add = (num1, num2) => num1 + num2;

export { add };
const doMath = async (num1, num2) => {
  if (num1 && num2) {
    const math = await import('./math.js');
    console.log(math.add(5, 10));
  };
};

doMath(4, 2);

似乎 Vue.js 动态引入组件就是这么干的~

结论

现在,感兴趣的朋友可以尝试去使用这个新规范了,如果不想装 babel 插件,可以直接在 chrome 浏览器中直接复制代码或者自定义编码~

快去试试吧~😋😋😋😋

  • ECMAScript
    3 引用 • 5 回帖
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1327 回帖
  • 分享

    有什么新发现就分享给大家吧!

    248 引用 • 1792 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • wizardforcel 1 评论

    空折叠和可选链式调用方便多了,比如这段代码:

    person?.profile?.name ?? "Anonymous"
    

    用 Java 写就是:

    Optional.ofNullable(person)
                .map(x -> x.profile)
                .map(x -> x.name)
                .orElse("Anonymous")
    

    也比 JS 的旧式方式优雅:

    person && person.profile && person.profile.name || "Anonymous"
    
    1 回复
    分化,有人会觉得问号后面加上点,很别扭,这块对插件也有要求
    Rabbitzzc
  • Rabbitzzc

    是的,但是有的开发者会觉得问号后面加上点,会觉得不是友好