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

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 等方法。

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

 1class Test { 2  a = 1;          // .a is public 3  #b = 2;         // .#b is private 4  static #c = 3;  // .#c is private and static 5  incB() { 6    this.#b++; 7  } 8} 9const testInstance = new Test();10// runs OK11testInstance.incB();12// error - private property cannot be modified outside class13testInstance.#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() 返回与正则表达式匹配的所有结果,包括捕获组。

1let regexp = /t(e)(st(\d?))/g;2let str = 'test1test2';let array = [...str.matchAll(regexp)];console.log(array[0]);3// expected output: Array ["test1", "e", "st1", "1"]

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

数字分隔

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

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

11000000000000 -> 1_000_000_000_00021019436871.42 -> 1_019_436_871.42

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

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

1const fileSystemPermission = 0b111_111_000;2const bytes = 0b1111_10101011_11110000_00001101;3const words = 0xFAB_F00D;

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

1const massOfElectronInKg = 9.109_383_56e-31;2const trillionInShortScale = 1e1_2;

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

BigInt

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

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

1const max = Number.MAX_SAFE_INTEGER;2// 90071992547409913max+1;4// 90071992547409925max+2;6// 9007199254740992

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

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

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

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

1BigInt(Number.MAX_SAFE_INTEGER) + 2n;2// 9007199254740993ntypeof 123n3// "bigint2"
   注意:数字分隔符对于BigInts尤其有用,例如: const massOfEarthInKg = 6_000_000_000_000_000_000_000_000n;   

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

1(7 + 6 - 5) * 4 ** 3 / 2 % 3;2// → 13(7n + 6n - 5n) * 4n ** 3n / 2n % 3n;4// → 1n
 注意:它不允许在 BigInts 和Numbers 之间进行混合运算。

BigInt 的语言环境字符串

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

 1let bigint = 123456789123456789n; 2 3// 德国使用 thousands 4console.log(bigint.toLocaleString('de-DE')); 5// → 123.456.789.123.456.789 6 7//在大多数说阿拉伯语的国家中,阿拉伯语使用东部阿拉伯数字 8console.log(bigint.toLocaleString('ar-EG')); 9// → ١٢٣٬٤٥٦٬٧٨٩٬١٢٣٬٤٥٦٬٧٨٩1011// 印度使用 thousands/lakh/crore 分隔符12console.log(bigint.toLocaleString('en-IN'));13// → 1,23,45,67,89,12,34,56,7891415// nu 扩展用于请求编号系统,例如 中文数字16console.log(bigint.toLocaleString('zh-Hans-CN-u-nu-hanidec'));17// → 一二三,四五六,七八九,一二三,四五六,七八九1819// 请求不支持的语言(例如巴厘语)时,请使用后备语言(在这种情况下为印尼语)20console.log(bigint.toLocaleString(['ban', 'id']));21// → 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】

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

1const getGlobalThis = () => { 2 3  // 在 webworker 或 service worker 中 4  if (typeof self !== 'undefined') return self; 5 6  // 在浏览器中 7  if (typeof window !== 'undefined') return window; 8 9  // 在 Node.js 中10  if (typeof global !== 'undefined') return global;1112  // 独立的 JavaScript shell13  if (typeof this !== 'undefined') return this;1415  throw new Error('Unable to locate global object');16};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 的结果。

1const promise1 = Promise.resolve(3);2const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));3const promises = [promise1, promise2];Promise.allSettled(promises).4  then((results) => results.forEach((result) => console.log(result.status)));5// 预期输出:6// "fulfilled"7// "rejected"

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

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

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

动态导入

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

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

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

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

1import * as module from './utils.mjs';

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

但是以下这些:

  • 按需(或有条件)导入模块

  • 在运行时计算模块说明符

  • 从常规脚本(而不是模块)中导入模块

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

1<script type="module"> 2  (async () => { 3    const moduleSpecifier = './utils.mjs'; 4    const module = await import(moduleSpecifier) 5    module.default(); 6    // → logs 'Hi from the default export!' 7    module.doStuff(); 8    // → logs 'Doing stuff…' 9  })();10</script>
  注意:对于初始化绘制依赖项,尤其是首屏内容时请使用静态 import。在其他情况下,考虑用动态 import()按需加载依赖项。

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

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

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

 1const people =  [ 2  {name: 'Gary', age: 20}, 3  {name: 'Ann', age: 20}, 4  {name: 'Bob', age: 17}, 5  {name: 'Sue', age: 21}, 6  {name: 'Sam', age: 17}, 7]; 8// Sort people by name 9people.sort( (p1, p2) => {10  if (p1.name < p2.name) return -1;11  if (p1.name > p2.name) return 1;12  return 0;13});console.log(people.map(p => p.name));14// ['Ann', 'Bob', 'Gary', 'Sam', 'Sue']15// Re-sort people by age16people.sort( (p1, p2) => {17  if (p1.age < p2.age) return -1;18  if (p1.age > p2.age) return 1;19  return 0;20});console.log(people.map(p => p.name));21// 我们期望先按年龄,然后按年龄组中的姓名排序:22// ['Bob', 'Sam', 'Ann', 'Gary', 'Sue']23// 但是我们可能会得到其中的任何一种,这取决于浏览器:24// ['Sam', 'Bob', 'Ann', 'Gary', 'Sue']25// ['Bob', 'Sam', 'Gary', 'Ann', 'Sue']26// ['Sam', 'Bob', 'Gary', 'Ann', 'Sue']

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

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

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

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

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

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

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

更多相关文章

  1. 通过jQuery设置全局Ajax加载时呈现Loading
  2. 在解释语言上使用非常大的整数时,会产生意想不到的结果。
  3. PHP平均整数红包算法
  4. 如何从0-X的PHP中获得一个加密的强整数?
  5. 您是否认为PHP中的错误形式是在类方法中访问超级全局变量?
  6. 【转】MySQL分库分表环境下全局ID生成方案
  7. 在平台上获取,可移植,更大和更快(无符号)的整数类型
  8. Safari / Chrome中的全局控制台对象被重置
  9. JavaScript - 检查是否在全局上下文中

随机推荐

  1. 当锚标记被单击时,角值从一个页面传递到另
  2. jQuery .load停止嵌入页面/重新加载整个
  3. “/图标。ico " vs
  4. 我无法理解为什么我的代码中的单击选择文
  5. 儿童视图不在angular-ui-router中工作
  6. jQuery延迟淡入时间超过预期
  7. word和.txt文件转html 及pdf文件, 使用poi
  8. 在HTML中添加<br /为何整篇内容却全部顶
  9. asp:Repeater 动态换行
  10. 是否可以将HTML元素固定到另一个的底部?