共计 7180 个字符,预计需要花费 18 分钟才能阅读完成。
感兴趣的能够加微信群
如果过期能够底下留言,或者关注我的微信公众号《人生代码》《人生代码》《人生代码》,回复进群,加我微信,拉你进群,重要的事件说三遍。
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.url 为 URL 该类提供 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";
这种增加简化了您的代码,并使 import 和 export 语句之间放弃对称。
数据类型和对象
新的 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 不是 null 或 undefined。
可选的链接运算符(?.)使您能够领有更紧凑,更易读的代码,如下所示:
const txtName = document.getElementById("txtName");
const name = txtName?.value;
与后面的示例一样,该 name 常量的值将为 txtName.valueif txtNameis notnull 或 undefined;; 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_DOMAIN 和 YOUR_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 进行身份验证和受权的更多信息。