如果您今天编写JavaScript,那么值得您花时间了解该语言在过去几年中看到的所有更新。自2015年以来,随着ES6的发布,每年都会发布新版本的ECMAScript规范。每次迭代都为该语言添加了新功能,新语法和生活质量改进。大多数浏览器和Node.js中的JavaScript引擎很快就会赶上,并且您的代码也应该赶上也很公平。这是因为随着JavaScript的每次新迭代,都会出现新的习惯用法和新的方式来表达您的代码,而且很多时候,这些更改可能会使您和您的协作者更易于维护代码。
这里是一些最新的ECMAScript功能,通过归纳,JavaScript和Node.js,您可以利用它们编写更简洁,更简洁和更易读的代码。
1.整块计分声明 自从该语言问世以来,JavaScript开发人员一直var在声明变量。关键字var具有其怪癖,其中最成问题的是使用它创建的变量的范围。
var x = 10 if (true) { var x = 15 // inner declaration overrides declaration in parent scope console.log(x) // prints 15 } console.log(x) // prints 15
由于使用定义的变量var不是块作用域,因此在较窄的范围内重新定义它们会影响外部范围的值。
现在,我们有两个新的关键字replace var,即let,const并且没有这个缺点。
let y = 10 if (true) { let y = 15 // inner declaration is scoped within the if block console.log(y) // prints 15 } console.log(y) // prints 10
const并且let在语义上不同,用声明的变量const无法在其范围内重新分配。这并不意味着它们是不可变的,只是它们的引用不能更改。
const x = [] x.push("Hello", "World!") x // ["Hello", "World!"] x = [] // TypeError: Attempted to assign to readonly property.
2.Arrow Functions Arrow Functions是最近引入JavaScript的另一个非常重要的功能。它们具有许多优点。首先,它们使JavaScript的功能方面看起来更漂亮,并且编写起来更简单。
let x = [1, 2, 3, 4] x.map(val => val * 2) // [2, 4, 6, 8] x.filter(val => val % 2 == 0) // [2, 4] x.reduce((acc, val) => acc + val, 0) // 10
在以上所有示例中,以独特箭头命名的箭头=>函数用简洁的语法替换了传统函数。
如果函数主体是单个表达式,则隐含范围括号{}和return关键字,无需编写。 如果函数具有单个参数,则参数括号()是隐含的,无需编写。 如果函数体表达式是字典,则必须将其括在括号中()。 箭头函数的另一个重要优点是它们不定义范围,而是存在于父范围内。这样可以避免由于使用this关键字而引起的许多陷阱。箭头函数没有的绑定this。在arrow函数中,的值this与父作用域中的值相同。因此,箭头函数不能用作方法或构造函数。箭头函数不适用于apply,bind或call,也没有的绑定super。
它们还具有某些其他限制,例如缺少arguments传统功能可以访问的对象以及无法yield从功能主体访问。
因此,箭头功能不是标准功能的1:1替代,而是欢迎添加到JavaScript的功能集中。
3.可选链接 person在这里想象一个深嵌套的数据结构,像这个对象。考虑您要访问此人的名字和姓氏。您可以这样用JavaScript编写此代码:
person = { name: { first: 'John', last: 'Doe', }, age: 42 } person.name.first // 'John' person.name.last // 'Doe'
现在想象一下,如果person对象不包含嵌套name对象,将会发生什么。
person = { age: 42 } person.name.first // TypeError: Cannot read property 'first' of undefined person.name.last // TypeError: Cannot read property 'last' of undefined
为避免此类错误,开发人员不得不诉诸如下代码,这些代码不必要地冗长,难以阅读且难以编写,这是一个非常糟糕的形容词三重奏。
person && person.name && person.name.first // undefined
满足可选链接的要求,这是JavaScript的一项新功能,可以消除这种怪异现象。可选的链接会在挖掘过程遇到anull或undefinedvalue并返回undefined而不会引起错误的情况下将其短路。
person?.name?.first // undefined
结果代码简洁明了。
4.空合并 在引入空值合并运算符之前,JavaScript开发人员使用OR运算符||(如果缺少输入)回退到默认值。这带有重大警告,即使合法但虚假的值也将导致默认值的回退。
function print(val) { return val || 'Missing' } print(undefined) // 'Missing' print(null) // 'Missing' print(0) // 'Missing' print('') // 'Missing' print(false) // 'Missing' print(NaN) // 'Missing'
JavaScript现在已经提出了null合并运算符??,它提供了一个更好的选择,因为只有在前面的表达式为null-ish的情况下,它才会导致回退。此处的空值是指null或的值undefined。
function print(val) { return val ?? 'Missing' } print(undefined) // 'Missing' print(null) // 'Missing' print(0) // 0 print('') // '' print(false) // false print(NaN) // NaN
这样,您可以确保如果程序接受伪造的值作为合法输入,则不会最终将其替换为后备。
5.逻辑分配 假设您要在且仅当该值当前为空时才为该变量分配一个值。逻辑上这样写是这样的:
if (x === null || x == undefined) { x = y }
如果您知道短路的工作原理,则可能希望使用零位合并运算符将这三行代码替换为更简洁的版本。
x ?? (x = y) // x = y if x is nullish, else no effect
在这里,我们使用null ish合并运算符的短路功能来执行第二部分(x = y如果x为null ish的话)。该代码非常简洁,但仍不太容易阅读或理解。逻辑为零的分配消除了这种变通方法的需要。
x ??= y // x = y if x is nullish, else no effect
同样,JavaScript还引入了逻辑AND赋值&&=和逻辑OR赋值||=运算符。这些操作员仅在满足特定条件时执行分配,否则不起作用。
x ||= y // x = y if x is falsy, else no effect x &&= y // x = y if x is truthy, else no effect
专家提示:如果您以前已经编写过Ruby,那么您会看到||=and&&=运算符,因为Ruby没有虚假值的概念。
6.命名捕获组 让我们开始快速回顾一下正则表达式中的捕获组。捕获组是与括号中的正则表达式部分匹配的字符串的一部分。
let re = /(\d{4})-(\d{2})-(\d{2})/ let result = re.exec('Pi day this year falls on 2021-03-14!') result[0] // '2020-03-14', the complete match result[1] // '2020', the first capture group result[2] // '03', the second capture group result[3] // '14', the third capture group
正则表达式在相当长的一段时间内也支持命名捕获组,这是通过名称而不是索引引用捕获组的一种方式。现在,在ES9中,此功能已实现了JavaScript的发展。现在,结果对象包含一个嵌套的组对象,其中每个捕获组的值都映射到其名称。
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ let result = re.exec('Pi day this year falls on 2021-03-14!') result.groups.year // '2020', the group named 'year' result.groups.month // '03', the group named 'month' result.groups.day // '14', the group named 'day'
新的API与另一种新的JavaScript功能(解构的分配)完美地结合在一起。
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ let result = re.exec('Pi day this year falls on 2021-03-14!') let { year, month, day } = result.groups year // '2020' month // '03' day // '14'
7.async和await JavaScript的强大功能之一就是它的异步性。这意味着许多可能长时间运行或耗时的函数可以返回Promise而不阻止执行。
const url = 'https://the-one-api.dev/v2/book' let prom = fetch(url) prom // Promise {<pending>} // wait a bit prom // Promise {<fullfilled>: Response}, if no errors // or prom // Promise {<rejected>: Error message}, if any error
在这里,对fetch的调用返回一个Promise,该Promise在创建时的状态为“待处理”。很快,当API返回响应时,它将转换为“已实现”状态,并且可以访问包装的响应。在Promises世界中,您将执行以下操作来进行API调用并将响应解析为JSON。
const url = 'https://the-one-api.dev/v2/book' let prom = fetch(url) prom // Promise {<fullfilled>: Response} .then(res => res.json()) .then(json => console.log(json)) // prints response, if no errors .catch(err => console.log(err)) // prints error message, if any error
在2017年,JavaScript宣布了两个新的关键字async和await,使Promises的处理和使用变得更加轻松和流畅。它们不能替代Promises;它们只是强大的Promises概念之上的语法糖。
而不是让所有代码都出现在一系列“ then”函数内,await而是使它们看上去都像同步JavaScript。另外一个好处是,您可以使用try...catchwithawait而不是像直接使用Promises那样处理'catch'函数中的错误。相同的代码await如下所示。
const url = 'https://the-one-api.dev/v2/book' let res = await fetch(url) // Promise {<fullfilled>: Response} -await-> Response try { let json = await res.json() console.log(json) // prints response, if no errors } catch(err) { console.log(err) // prints error message, if any error }
该async关键字是相同的硬币的另一侧,在它包装的任何数据到一个无极内被发送。考虑以下异步函数以添加多个数字。在现实世界中,您的代码将执行更为复杂的操作。
async function sum(...nums) { return nums.reduce((agg, val) => agg + val, 0) } sum(1, 2, 3) // Promise {<fulfilled>: 6} .then(res => console.log(res) // prints 6 let res = await sum(1, 2, 3) // Promise {<fulfilled>: 6} -await-> 6 console.log(res) // prints 6
结论 这些新功能只是冰山一角。我们几乎没有刮过表面。JavaScript不断发展,并且每年都会在语言中添加新功能。很难跟上手动引入该语言的新功能和惯用语言的不断涌入。
如果某些工具可以为我们解决这个问题,那不是很好吗?不用,那里。我们已经详细讨论了使用ESLint在JavaScript存储库中设置静态代码分析的问题。它非常有用,应该是您工具链中必不可少的工具。但老实说,设置ESLint自动修复管道和流程需要花费时间和精力。除非您喜欢这种管道,否则如果您编写代码并将管道外包给DeepSource会更好。
DeepSource可以帮助您自动执行代码审查,并节省大量时间。只需.deepsource.toml在存储库的根目录中添加一个文件,DeepSource便会立即选择要扫描的文件。扫描将发现整个代码的改进范围,并通过有用的说明帮助您修复它们。
原文链接:https://codingdict.com/