前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Javascript 的新功能-Part 1[每日前端夜话0xC6]

Javascript 的新功能-Part 1[每日前端夜话0xC6]

作者头像
疯狂的技术宅
发布2019-09-25 16:04:04
8480
发布2019-09-25 16:04:04
举报
文章被收录于专栏:京程一灯

作者:Deepak Gupta

翻译:疯狂的技术宅

来源:medium

JavaScript 的应用领域已经从 Web 浏览器扩展到所有需要编程的地方。

  1. Node.js — 用于CLI和服务器。
  2. Electron — 用于跨平台的桌面应用程序。
  3. React native — 用于跨平台的移动应用。
  4. IoT — 低成本物联网设备现在开始支持 javascript。

最近更新的 V8 引擎使性能提升了不少。JavaScript 解析速度提高了 2 倍甚至更快,从node v8.0开始,node v11以上版本的平均速度比 node v8.0 提高了 11 倍。内存消耗减少了 20%。在性能和可用性上有了全面改善。

在本文中,我们将看到一些可以在Chrome浏览器(版本 ≥ 76)或 Node.js(版本 ≥ 11)CLI 中测试的 ES10 强大功能。

私有类字段

在ES6之前,我们无法直接申请 private 属性。是的,有下划线约定(_propertyName)、闭包、 symbols 或 WeakMaps 等方法。

但现在私有类字段可以使用哈希前缀 # 来定义。让我们通过实例学习它

代码语言:javascript
复制
class Test {
  a = 1;          // .a is public
  #b = 2;         // .#b is private
  static #c = 3;  // .#c is private and static
  incB() {
    this.#b++;
  }
}
const testInstance = new Test();
// runs OK
testInstance.incB();
// error - private property cannot be modified outside class
testInstance.#b = 0;

注意:截至目前,没有办法定义私有函数,尽管 TC39 第 3 阶段:建议草案【https://github.com/tc39/proposal-private-methods】建议在名字上使用散列前缀?

String.matchAll()?

如果我有一个字符串,其中有多个全局正则表达式捕获组,我经常想要遍历所有匹配。目前,我的选择有以下几种:

  1. RegExp.prototype.exec() with /g — 我们可以称之为 .exec() 多次获得一个正则表达式的匹配。它为每个匹配返回一个匹配对象,最后返回 null。
  2. String.prototype.match() with /g — 如果我们通过 .match() 使用正则表达式,设置其标志为 /g ,你会得到一个完全匹配的数组。
  3. String.prototype.split() — 如果我们使用分割字符串和正则表达式来指定分隔符,并且它至少包含一个捕获组,那么 .split() 将返回一个子串交错的数组。

上述方法的问题在于,只有在正则表达式上设置 /g 并且每次匹配时对正则表达式的属性 .lastIndex 进行更改时,它们才起作用。这使得在多个位置使用相同的正则表达式存在风险。

matchAll() 能够帮助解决以上所有问题。让我们看看它的定义和使用:

给定字符串和正则表达式,.matchAll() 返回与正则表达式匹配的所有结果,包括捕获组。

代码语言:javascript
复制
let regexp = /t(e)(st(\d?))/g;
let str = 'test1test2';let array = [...str.matchAll(regexp)];console.log(array[0]);
// expected output: Array ["test1", "e", "st1", "1"]

注意:.matchAll() 返回一个迭代器,但它不是真正的可重启迭代器。也就是说一旦结果耗尽,则需要再次调用该方法并创建一个新的迭代器。

数字分隔?

如果你一直在努力去读较长的数字序列,那么这就是你要找的。

数字分隔符使人眼能够快速解析,尤其是当有很多重复的数字时:

代码语言:javascript
复制
1000000000000 -> 1_000_000_000_000
1019436871.42 -> 1_019_436_871.42

现在,更容易说出第一个数字是1万亿,而第二个数字是10亿。

这也适用于其他进制,例如:

代码语言:javascript
复制
const fileSystemPermission = 0b111_111_000;
const bytes = 0b1111_10101011_11110000_00001101;
const words = 0xFAB_F00D;

你还可以用在分数和指数中:

代码语言:javascript
复制
const massOfElectronInKg = 9.109_383_56e-31;
const trillionInShortScale = 1e1_2;

注意:解析带有 _ 分隔的整数可能很棘手,因为Number('123_456') 会给出 NAN,而 parseInt('123_456') 则给出 123

BigInt?

BigInts 是 JavaScript 中的一种新的数字原语,可以表示精度比2⁵³-1更大的整数。使用 BigInts,你可以安全地存储和操作大整数,甚至可以超出 Numbers 的安全整数限制。

BigInts 可以正确执行整数运算而不会溢出。让我们通过一个例子来理解:

代码语言:javascript
复制
const max = Number.MAX_SAFE_INTEGER;
// 9007199254740991
max+1;
// 9007199254740992
max+2;
// 9007199254740992

我们可以看到 max + 1 产生的结果与 max + 2 相同。

任何超出安全整数范围(即从 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER)的整数的计算都可能会失去精度。所以我们只能依赖安全范围内的数字整型的值。

BigInts 应运而生,可以通过将 n 后缀添加到整数文字中来创建 BigInts 。例如,123 变成 123n,或者全局 BigInt(number) 函数可用于将 Number 转换为 BigInts

让我们重新看一下上面的 BigInt 例子

代码语言:javascript
复制
BigInt(Number.MAX_SAFE_INTEGER) + 2n;
// 9007199254740993ntypeof 123n
// "bigint2"

注意:数字分隔符对于BigInts尤其有用,例如: const massOfEarthInKg = 6_000_000_000_000_000_000_000_000n;

BigInts 支持最常见的运算符。二进制 +-*** 均按预期工作。/ 工作时根据需要四舍五入。

代码语言:javascript
复制
(7 + 6 - 5) * 4 ** 3 / 2 % 3;
// → 1
(7n + 6n - 5n) * 4n ** 3n / 2n % 3n;
// → 1n

注意:它不允许在 BigIntsNumbers 之间进行混合运算。

BigInt 的语言环境字符串?

toLocaleString() 方法返回一个字符串,该字符串具有 BigInt 的语言敏感表示形式。

代码语言:javascript
复制
let bigint = 123456789123456789n;

// 德国使用 thousands
console.log(bigint.toLocaleString('de-DE'));
// → 123.456.789.123.456.789

//在大多数说阿拉伯语的国家中,阿拉伯语使用东部阿拉伯数字
console.log(bigint.toLocaleString('ar-EG'));
// → ١٢٣٬٤٥٦٬٧٨٩٬١٢٣٬٤٥٦٬٧٨٩

// 印度使用 thousands/lakh/crore 分隔符
console.log(bigint.toLocaleString('en-IN'));
// → 1,23,45,67,89,12,34,56,789

// nu 扩展用于请求编号系统,例如 中文数字
console.log(bigint.toLocaleString('zh-Hans-CN-u-nu-hanidec'));
// → 一二三,四五六,七八九,一二三,四五六,七八九

// 请求不支持的语言(例如巴厘语)时,请使用后备语言(在这种情况下为印尼语)
console.log(bigint.toLocaleString(['ban', 'id']));
// → 123.456.789.123.456.789

globalThis 关键字?

JavaScript 的变量作用域被嵌套并形成树结构,其根是全局作用域,this 关键字的值是对 “拥有” 当前正在执行的代码或所查看函数的对象的引用。

要了解有关此关键字和全局作用一的更多信息,请阅读以下文章

Scopes in Javascript【https://medium.com/datadriveninvestor/still-confused-in-js-scopes-f7dae62c16ee】 Understanding Javascript ‘this’ keyword (Context)【https://medium.com/datadriveninvestor/javascript-context-this-keyword-9a78a19d5786】

通常要弄清楚全局作用域,我们使用这样的函数

代码语言:javascript
复制
const getGlobalThis = () => {

  // 在 webworker 或 service worker 中
  if (typeof self !== 'undefined') return self;

  // 在浏览器中
  if (typeof window !== 'undefined') return window;

  // 在 Node.js 中
  if (typeof global !== 'undefined') return global;

  // 独立的 JavaScript shell
  if (typeof this !== 'undefined') return this;

  throw new Error('Unable to locate global object');
};const theGlobalThis = getGlobalThis();

以上函数并不涵盖全局变量的所有情况。

  1. 如果使用strict,则其值是 undefined
  2. 当我们在 javascript 中形成捆绑包时,通常会在一些可能与此全局代码不同的代码下进行包装。
  3. 在独立的 JavaScript 引擎 shell 环境中,以上代码将不起作用

为了解决上述问题,引入了 globalThis 关键字,该关键字可以在任何环境下随时返回全局对象。

注意:为了保持向后兼容,现在全局对象被认为是 JavaScript 无法消除的错误。它会对性能产生负面影响,并经常使人困惑。

Promise.allSettled()?

如果你想知道 JavaScript Promise 的用途,请查看此内容 —— JavaScript Promises:简介【https://developers.google.com/web/fundamentals/primers/promises】。

Promise 是 JavaScript 向你承诺工作将要完成的方式(如果工作无法完成,则可能会失败)。

新方法会返回一个 Promise ,它会在所有给定的 Promise 均已解决(即已解决或拒绝)之后解决,并带有一系列对象,一个对象描述一个 Promise 的结果。

代码语言:javascript
复制
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)));
// 预期输出:
// "fulfilled"
// "rejected"

这与 Promise.all 不同,因为 Promise.all 在可迭代对象中的 Promise 被拒绝后就立即拒绝。

下面是当前支持的 promise 方法的比较

Short-circuit?

Short-circuits on?

Fulfilled on?

Rejected on?

Promise.all

First rejected promise

All promise fulfilled

First rejected promise

Promise.allSettled

N/A

Always

N/A

Promise.race

First settled

First promise fulfilled

First rejected promise

动态导入?

静态与动态导入

这个很疯狂,在我们深入研究它之前,先看看静态导入是什么。

静态导入仅接受字符串文字作为模块说明符,并通过运行前的“链接”过程将绑定引入本地作用域。

静态的 import 语法只能在文件的顶层使用。

代码语言:javascript
复制
import * as module from './utils.mjs';

静态 import 可以启用重要的用例,如静态分析、捆绑工具、和tree-shaking。

但是以下这些:

  • 按需(或有条件)导入模块
  • 在运行时计算模块说明符
  • 从常规脚本(而不是模块)中导入模块

动态导入出现之前是不可能的 — import(moduleSpecifier) 返回所请求模块的模块命名空间对象的promise,它是在提取、实例化和评估模块的所有依赖关系以及模块本身之后才创建的。

代码语言:javascript
复制
<script type="module">
  (async () => {
    const moduleSpecifier = './utils.mjs';
    const module = await import(moduleSpecifier)
    module.default();
    // → logs 'Hi from the default export!'
    module.doStuff();
    // → logs 'Doing stuff…'
  })();
</script>

注意:对于初始化绘制依赖项,尤其是首屏内容时请使用静态 import。在其他情况下,考虑用动态 import()按需加载依赖项。

稳定排序(现在能够得到一致和可靠的结果)?

稳定在算法意义【https://en.wikipedia.org/wiki/Sorting_algorithm#Stability】上的意思是:它是保留顺序,还是仅保证项目“相等”

让我们通过一个例子理解它:

代码语言:javascript
复制
const people = [
  {name: 'Gary', age: 20},
  {name: 'Ann', age: 20},
  {name: 'Bob', age: 17},
  {name: 'Sue', age: 21},
  {name: 'Sam', age: 17},
];
// Sort people by name
people.sort( (p1, p2) => {
  if (p1.name < p2.name) return -1;
  if (p1.name > p2.name) return 1;
  return 0;
});console.log(people.map(p => p.name));
// ['Ann', 'Bob', 'Gary', 'Sam', 'Sue']
// Re-sort people by age
people.sort( (p1, p2) => {
  if (p1.age < p2.age) return -1;
  if (p1.age > p2.age) return 1;
  return 0;
});console.log(people.map(p => p.name));
// 我们期望先按年龄,然后按年龄组中的姓名排序:
// ['Bob', 'Sam', 'Ann', 'Gary', 'Sue']
// 但是我们可能会得到其中的任何一种,这取决于浏览器:
// ['Sam', 'Bob', 'Ann', 'Gary', 'Sue']
// ['Bob', 'Sam', 'Gary', 'Ann', 'Sue']
// ['Sam', 'Bob', 'Gary', 'Ann', 'Sue']

如果你得到的是最后三个结果之一,则可能是你用的是 Google Chrome 浏览器,或者可能是没有将 Array.sort()实现为“稳定”算法的各种浏览器之一。

这是因为不同的 JS 引擎(在不同的浏览器上)采用了不同的路径来实现排序,而且某些 JavaScript 引擎对短数组使用稳定的排序,而对长数组使用不稳定的排序。

这就导致了因为排序稳定性的行为不一致而引发了很多混乱。这就是为什么在开发环境中与排序相关的内容似乎都可以工作,但是在生产环境中,由于和测试排序所使用的数组大小不同,我们开始看到其他内容的原因。

注意:有一些第三方库,我强烈衷心推荐 Lodash,它能够提供稳定的排序

但这些问题已经解决,我们在大多数浏览器上都能得到稳定的排序,同时语法保持不变。

由于本文有很多知识点和需要实际测试的功能,所以我们将在下一篇文章中继续介绍更多的新功能。

原文:https://medium.com/@ideepak.jsd/javascript-new-features-part-1-f1a4360466

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端先锋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 私有类字段
  • String.matchAll()?
  • 数字分隔?
  • BigInt?
  • BigInt 的语言环境字符串?
  • globalThis 关键字?
  • Promise.allSettled()?
  • 动态导入?
  • 稳定排序(现在能够得到一致和可靠的结果)?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档