前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript:ECMAScript 2020中的新增功能

JavaScript:ECMAScript 2020中的新增功能

作者头像
公众号---人生代码
发布2020-10-22 10:39:35
1.9K0
发布2020-10-22 10:39:35
举报
文章被收录于专栏:人生代码人生代码

JavaScript即将推出令人兴奋的新功能!

即使新ECMAScript 2020(ES2020)语言规范的最终批准已经在六月,您也可以立即开始尝试一下!

处理模块

一些重要的创新涉及模块。其中,开发人员长期以来一直要求的功能是动态导入。但是,让我们按顺序进行详细介绍。

动态导入

当前的模块导入机制基于静态声明,如下所示:

import * as MyModule from "./my-module.js";

该语句有两个约束:

在当前模块的加载时间评估导入模块的所有代码

该模块的说明符("./my-module.js"在上面的示例中)是一个字符串常量,您不能在运行时更改它

这些约束阻止有条件或按需加载模块。同样,在加载时评估每个相关模块也会影响应用程序的性能。

import()语句通过允许您动态导入模块来解决了这些问题。该语句接受模块说明符作为参数并返回promise。同样,模块说明符可以是任何返回字符串的表达式。这是个好消息,因为我们现在可以在运行时加载JavaScript模块,如以下示例所示:

const baseModulePath = "./modules";
const btnBooks = document.getElementById("btnBooks");
let bookList = [];

btnBooks.addEventListener("click", async e => {
  const bookModule = await import(`${baseModulePath}/books.js`);

  bookList = bookModule.loadList();
});

该代码显示books.js了用户单击btnBooks按钮时如何正确加载模块。加载模块后,click事件处理程序将使用loadList()模块导出的功能。请注意如何通过字符串插值指定要导入的模块。

导入元数据

import.meta对象提供当前模块的元数据。JavaScript引擎创建了它,其当前可用属性为url。此属性的值是从中加载模块的URL,包括任何查询参数或哈希。

例如,您可以使用该import.meta.url属性来构建data.json存储在当前模块相同文件夹中的文件的URL 。以下代码获得此结果:

const dataUrl = new URL("data.json", import.meta.url);

在这种情况下,会import.meta.urlURL该类提供data.json文件的基本URL 。

新的导出语法

importECMAScript 2015规范引入的声明为您提供了多种形式的模块导入。以下是一些示例:

import {value} from "./my-module.js";
import * from "./my-module.js";

在某些情况下,您可能需要导出从另一个模块导入的对象。方便的export语法可能会对您有所帮助,如下所示:

export {value} from "./my-module.js";
export * from "./my-module.js";

从开发人员的经验来看,导入和导出语句之间的这种对称性很方便。但是,在这些新规范之前不支持特定情况:

import * as MyModule from "./my-module.js";

要导出MyModule名称空间,应使用两个语句:

import * as MyModule from "./my-module.js";
export {MyModule};

现在,您可以通过一条语句获得相同的结果,如下所示:

export * as MyModule from "./my-module.js";

这种添加简化了您的代码,并使importexport语句之间保持对称。

数据类型和对象

新的ES2020规范引入了新的数据类型,标准化的全局对象以及一些简化开发人员生活的方法。让我们来看看。

BigInt和任意精度整数

如您所知,JavaScript只有一种数据类型:数字Number。这种原始类型允许您表示64位浮点数。当然,它也表示整数,但是最大可表示值为2 53,对应于Number.MAX_SAFE_INTEGER常数。

在不涉及整数表示的内部细节的情况下,有些情况下您可能需要更高的精度。考虑以下情况:

与其他提供64位整数数据的系统(例如GUID,帐号或对象ID)进行交互

需要超过64位的复杂数学计算的结果

第一种情况的解决方法是将数据表示为字符串。当然,这种解决方法不适用于第二种情况。

新的BigInt数据类型旨在解决这些问题。您可以BigInt通过将字母简单地附加n到数字来表示文字,如以下示例所示:

const aBigInteger = 98765432123456789n;

您也可以像使用BigInt()构造函数一样使用Number()构造函数:

const aBigInteger = BigInt("98765432123456789");

typeof现在,运算符将"bigint"应用于BigInt值的字符串返回:

typeof aBigInteger      //output: "bigint"

请记住,Number并且BigInt是不同类型的,所以你不能将它们混合。例如,尝试将Number值添加到BigInt值会引发TypeError异常,如下图所示:

您必须使用构造函数将Number值显式转换为值。BigIntBigInt()

用于正则表达式的matchAll()方法

您可以通过多种方式获取给定正则表达式的所有匹配项。以下是这些方法之一,但是您可以使用其他方法:

const regExp = /page (\d+)/g;
const text = 'text page 1 text text page 2';
let matches;

while ((matches = regExp.exec(text)) !== null) {
  console.log(matches);
}

此代码通过迭代匹配变量中的所有page x实例text。在每次迭代时,该exec()方法都会在输入字符串上运行,并且您将获得如下结果:

["page 1", "1", index: 5, input: "text page 1 text text page 2", groups: undefined]
["page 2", "2", index: 22, input: "text page 1 text text page 2", groups: undefined]

matchAll()方法String的对象,您可以得到相同的结果,但在更紧凑的方式和更好的性能。下面的示例使用此新方法重写以前的代码:

const regExp = /page (\d+)/g;
const text = 'text page 1 text text page 2';
let matches = [...text.matchAll(regExp)];

for (const match of matches) {
  console.log(match);
}

matchAll()方法返回一个迭代器。前面的示例使用传播运算符将迭代器的结果收集到数组中。

全局对象

访问全局对象需要不同的语法,具体取决于JavaScript环境。例如,在浏览器中,全局对象是window,但是您不能在Web Worker中使用它。在这种情况下,您需要使用self。另外,在Node.js中,全局对象是global

在编写旨在在不同环境中运行的代码时,这会导致问题。您可能使用了this关键字,但是它undefined在以严格模式运行的模块和函数中。

globalThis对象提供了一种跨不同JavaScript环境访问全局对象的标准方法。因此,现在您可以以一致的方式编写代码,而不必检查当前的运行环境。但是请记住,要尽量减少使用全局项,因为这被认为是不好的编程习惯。

Promise.allSettled()方法

目前,JavaScript有两种方法来组合诺言:Promise.all()Promise.race()

两种方法都将一个promise数组作为参数。以下是使用示例Promise.all()

const promises = [fetch("/users"), fetch("/roles")];
const allResults = await Promise.all(promises);

Promise.all()当所有的诺言都实现时,返回一个诺言。如果至少一个诺言被拒绝,则返回的诺言被拒绝。最终承诺的拒绝原因与第一个拒绝的承诺相同。

当至少一个承诺被拒绝时,这种行为无法为您提供直接获得所有承诺结果的方法。例如,在上面的代码中,如果fetch("/users")失败并且相应的诺言被拒绝,您将没有一个简单的方法来知道的诺言fetch("/roles")是兑现还是被拒绝。要获得此信息,您必须编写一些其他代码。

新的Promise.allSettled()组合器将等待所有诺言的兑现,无论其结果如何。因此,以下代码可让您知道每个诺言的结果:

const promises = [fetch("/users"), fetch("/roles")];
const allResults = await Promise.allSettled(promises);
const errors = results
  .filter(p => p.status === 'rejected')
  .map(p => p.reason);

特别是,此代码使您知道每个被拒绝的承诺失败的原因。

新运营商

几个新的运算符将使在非常常见的操作中更容易编写和阅读代码。猜猜哪一个?

空合并运算符

您看过多少次并使用了以下表达式?

const size = settings.size || 42;

||当您尝试分配的默认值是null或时,通常使用运算符来分配默认值undefined。但是,这种方法可能会导致一些潜在的意外结果。

例如,size上面示例中的常量42也将在settings.sizeis的值时被赋值0。但是,当值的默认值也将被指定settings.size""false

为了克服这些潜在的问题,现在您可以使用无效的合并运算符??)。先前的代码如下:

const size = settings.size ?? 42;

这允许仅在值为is或时42将默认值分配给size常数。settings.sizenullundefined

可选链接

考虑以下示例:

const txtName = document.getElementById("txtName");
const name = txtName ? txtName.value : undefined;

txtName将从当前HTML文档中获得带有其标识符的文本框。但是,如果文档中不存在HTML元素,则txtName常量将为null。因此,在访问其value属性之前,必须确保txtName不是nullundefined

可选的链接运算符(?.)使您可以拥有更紧凑,更易读的代码,如下所示:

const txtName = document.getElementById("txtName");
const name = txtName?.value;

与前面的示例一样,该name常量的值将为txtName.valueif txtNameis notnullundefined;; undefined除此以外。

在如下所示的复杂表达式中,此运算符的优点得到了更多的赞赏:

const customerCity = invoice?.customer?.address?.city;

您还可以将可选的链接运算符应用于动态属性,如以下示例所示:

const userName = user?.["name"];

此外,它也适用于函数或方法调用:

const fullName = user.getFullName?.();

在这种情况下,如果该getFullName()方法存在,则将执行该方法。否则,表达式返回undefined

使用新功能

在整篇文章中,您对ES2020的新功能进行了概述,并且您可能想知道何时才能使用它们。

根据caniuse.com的资料,所有最近的主流浏览器(但Internet Explorer)已经支持ECMAScript 2020带来的新功能。但是,在撰写本文时,Safari并不支持新的BigInt数据类型和matchAll()方法。

在Node.js的最新版本,支持所有功能,以及包括动态导入的启用ECMAScript的模块。

最后,Babel和TypeScript等最受欢迎的编译器的最新版本也使您可以使用最新的ES2020功能。

旁:使用JavaScript进行Auth0身份验证

在Auth0,我们大量使用了全栈JavaScript来帮助客户管理用户身份,包括密码重置,创建,供应,阻止和删除用户。因此,毫无疑问,在JavaScript Web应用程序上使用我们的身份管理平台简直是小菜一碟。

Auth0提供了一个免费层,可以开始使用现代身份验证。签出,或在此处注册免费的Auth0帐户!

然后,转到Auth0信息中心的“应用程序”部分,然后单击“创建应用程序”。在显示的对话框上,设置应用程序的名称,然后选择“单页Web应用程序”作为应用程序类型:

创建应用程序后,单击“设置”,并记下分配给您的应用程序的域和客户端ID。另外,将“允许的回调URL”和“允许的注销URL”字段设置为将处理Auth0的登录和注销响应的页面的URL。在当前示例中,页面的URL将包含您要编写的代码(例如http://localhost:8080)。

现在,在您的JavaScript项目中,如下安装auth0-spa-js库:

npm install @auth0/auth0-spa-js

然后,在您的JavaScript应用中实现以下内容:

import createAuth0Client from '@auth0/auth0-spa-js';

let auth0Client;

async function createClient() {
  return await createAuth0Client({
    domain: 'YOUR_DOMAIN',
    client_id: 'YOUR_CLIENT_ID'
  });
}

async function login() {
  await auth0Client.loginWithRedirect();
}

function logout() {
  auth0Client.logout();
}

async function handleRedirectCallback() {
  const isAuthenticated = await auth0Client.isAuthenticated();

  if (!isAuthenticated) {
    const query = window.location.search;
    if (query.includes("code=") && query.includes("state=")) {
      await auth0Client.handleRedirectCallback();
      window.history.replaceState({}, document.title, "/");
    }
  }

  await updateUI();
}

async function updateUI() {
  const isAuthenticated = await auth0Client.isAuthenticated();

  const btnLogin = document.getElementById("btn-login");
  const btnLogout = document.getElementById("btn-logout");

  btnLogin.addEventListener("click", login);
  btnLogout.addEventListener("click", logout);

  btnLogin.style.display = (isAuthenticated ? "none" : "block");
  btnLogout.style.display = (isAuthenticated ? "block" : "none");

  if (isAuthenticated) {
    const username = document.getElementById("username");
    const user = await auth0Client.getUser();

    username.innerText = user.name;
  }
}

window.addEventListener("load", async () => {
  auth0Client = await createClient();

  await handleRedirectCallback()
});

YOUR_DOMAINYOUR_CLIENT_ID占位符替换为您在Auth0信息中心中找到的域和客户端ID的实际值。

然后,使用以下标记创建UI:

  <p>Welcome <span id="username"></span></p>
  <button type="submit" id="btn-login">Sign In</button>
  <button type="submit" id="btn-logout" style="display:none;">Sign Out</button>

您的应用程序已准备好通过Auth0进行身份验证!

请查看Auth0 SPA SDK文档,以了解有关使用JavaScript和Auth0进行身份验证和授权的更多信息。

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

本文分享自 CryptoCode 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 处理模块
    • 动态导入
      • 导入元数据
        • 新的导出语法
        • 数据类型和对象
          • BigInt和任意精度整数
            • 用于正则表达式的matchAll()方法
              • 全局对象
                • Promise.allSettled()方法
                • 新运营商
                  • 空合并运算符
                    • 可选链接
                    • 旁:使用JavaScript进行Auth0身份验证
                    相关产品与服务
                    多因子身份认证
                    多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档