17611538698
webmaster@21cto.com

2024 年 5 个令人兴奋的 JavaScript 新特性

前端 0 177 2024-03-27 12:16:09

图片

导读:在本文中,我们将探讨一些最令人兴奋和最受期待的 JavaScript 功能,这些功能预计将在 2024 年推出。

各位朋友好,我们来描述2024年在JavaScript中让人兴奋的5个特性。其中,以下提案很有可能进入今年的 ECMAScript 版本:

ECMAScript 更新

ES的新版本总是会引起开发者和业界的振奋。自从 ES6 更新以来,每年都会有新版本,我们预计今年(ES2 024)将在 6 月初左右发布。

ES6 将是本年度的一个大规模发布版本,是在其前身 ES 5发布后6年后发布的

而浏览器提供商和 JavaScript 开发者对大量需要采用和学习新特性感到不知所措。从那时起,为了防止新功能同时出现,导致过多的状态变化,每年都有一个发布周期。

每个年度发布周期涉及提出任何新功能,都会经由技术委员会讨论、评估和投票,然后再将其添加到语言特性中。此过程还允许浏览器在提案正式添加到语言之前尝试实现这些提案,这会帮助人们解决现实的问题。

如前所述,JavaScript(或 ECMAScript)的新功能由技术委员会 39 (TC39)决定。TC39 由来自所有主流浏览器供应商的代表以及 JavaScript 技术专家组成。他们定期开会讨论该语言的新功能以及如何实现这些功能。新功能以提案形式提出(可以由任何人提出),然后委员会成员投票决定每个提案是否可以进入下一阶段。

每个提案有 4 个阶段;一旦提案达到第 4 阶段,预计该功能将被包含在下一版本的 ES 中。

ES 规范的一个重要部分是它必须向后兼容。这意味着任何新功能都不能通过改变 ES 之前版本的工作方式来破坏互联网。因此,他们无法改变现有方法的工作方式,只能添加新方法,因为任何使用可能预先存在的方法运行的网站都将面临崩溃的风险。

ES 规范的一个重要部分是它必须向后兼容。这意味着任何新功能都不能通过改变 ES 之前版本的工作方式来破坏Web应用。因此,他们无法改变现有方法的工作方式,只能添加新方法,因为任何使用可能预先存在的方法运行的网站都将面临崩溃的风险。

Temporal API

在《2022 年 JavaScript 现状》调查中,第三个最常见的答案是“你认为 JavaScript 目前缺少什么?” 是更好的日期管理。

这引发了Temporal 提案的产生,它提供了一个标准的全局对象来替换该Date对象,并修复了多年来在 JavaScript 中处理日期时给开发者带来很大痛苦的一些问题。

在 JavaScript 中处理日期几乎总是一项可怕的任务;必须处理微小但令人恼火的不一致,例如月份索引为零,实际上月份中的日期是从 1 开始的。

日期的使用困难,导致流行的外部库如Moment、Day.JS和date-fns出现,它们都试图解决这些问题。

但是,Temporal API 旨在本地解决所有问题。

Temporal将支持多个时与开箱即用的非公历特性,并将提供一个简单易用的 API,使使字符串解析日期变得更加容易。此外,所有Temporal对象都是不可变的,这将有助于避免任何意外的日期更改错误。

让我们看一下 API 提供的最有用方法的一些示例Temporal:

Temporal.Now.Instant()

Temporal.Now.Instant()将返回一个最接近纳秒的 DateTime 对象。您可以使用from如下方法指定特定日期:

const olympics = Temporal.Instant.from('2024-07-26T20:24:00+01:00');

这这个方法将创建一个 DateTime 对象,表示今年晚些时候巴黎奥运会将于 2024 年 7 月 26 日 20:24(UTC)开始。

PlainDate()

这个方法允许你只创建一个日期,没有时间:

new Temporal.PlainDate(2024, 7, 26);
Temporal.PlainDate.from('2024-07-26');
// both return a PlainDate object that represents 26th July 2024


PlainTime()

作为 PlainDate()的补充,我们可以使用这个新函数来创建一个没有日期的时间,使用.PlainTime()示例如下:

new Temporal.PlainTime(20, 24, 0);
Temporal.PlainTime.from('20:24:00');
// both return a PlainTime object of 20:24


PlainMonthDay()

PlainMonthDay() 类似PlainDate,但它只返回月份和日期,没有年份信息(对于每年在同一天重复出现的日期非常有用,例如圣诞节和情人节等):

const valentinesDay = Temporal.PlainMonthDay.from({ month: 2, day: 14 });


PlainYearMonth()

同样,还有PlainYearMonth只返回年份和月份(对于表示一年中的整个月份很有用):

const march = Temporal.PlainYearMonth.from({ month: 3, year: 2024 });


计算

可以使用 Temporal 对象完成许多计算。我们可以向日期对象添加和减去各种时间单位:

const today = Temporal.Now.plainDateISO();
const lastWeek = today.subtract({ days: 7});
const nextWeek = today.add({ days: 7 });


与until方法配合,since可让你了解距某个特定日期或自该日期发生以来的时间。例如,以下代码将告诉你距离巴黎奥运会还有多少天:

olympics.until().days
valentinesDay.since().hours

这些方法会返回一个Temporal.Duration对象,该对象可用于测量具有多种不同单位和舍入选项的时间量。

附加功能

我们可以从 Date 对象中提取年、月、日,并从 Time 对象中提取时、分、秒、毫秒、微秒和纳秒(微秒和纳秒在当前 DateTime 对象中不可用)。

类似下列代码:

olympics.hour;
<< 20


此外,还有其他属性,例如dayOfWeek(返回1星期一和7星期日)、daysInMonth(返回28, 29,30或31取决于月份) 和daysinYear(返回365或366,这取决于是否闰年)。

Temporal日期对象还有一个compare方法,可用于使用各种排序算法对日期进行排序。

Temporal 目前是在第 3 阶段提案,浏览器提供商正在实施该提案,因此似乎它的时机“已经到来”。

我们可以到以下地址查看完整文档:

https://tc39.es/proposal-temporal/docs/ 

这里还有一本有用的用例实用手册:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat

与Intl.DateTimeFormat API配合使用时,你将能够执行一些非常漂亮的日期操作。

Pipe Operator(管道操作符/管道运算符)

在2023 年 JavaScript 现状调查中,“你认为 JavaScript 目前缺少什么?”的第六个热门答案是管道操作符。

你可以在以下地址查看Pipe Operator 的详细提案:

https://github.com/tc39/proposal-pipeline-operator

管道运算符是函数式语言中的一项标准功能,它允许你将值从一个函数“管道”到另一个函数,前一个函数的输出用作下一个函数的输入(类似于 Fetch API 传递它从一个承诺返回到下一个承诺的任何数据)。

例如,假设我们想要连续将三个函数应用于一个字符串:

  1. 连接字符串“Listen up!” 到原始字符串的开头。

  2. 将三个感叹号连接到字符串的末尾。

  3. 将所有文本设为大写。


这三个函数可以写成如下代码:

const exclaim = string => string + "!!!"
const listen = string => "Listen up! " + string
const uppercase = string => string.toUpperCase()


这三个函数可以通过将它们全部嵌套在一起来应用,如下代码:

const text = "Hello World"
uppercase(exclaim(listen(text)))
<< "LISTEN UP! HELLO WORLD!!!"


但是,像这样深度嵌套多个函数调用可能会很快变得混乱,特别是因为text作为参数传递的值 ,括号( ) 最终深深嵌入到表达式中,使其非常难以识别。

函数嵌套的另一个问题是函数的应用顺序是从后到前的,即最里面的函数首先被应用。因此,在这种情况下,listengets 应用于原始值text,然后,最后将应用exclaim最外层函数。uppercase函数特别是对于大型且复杂的项目时,会变得很难看并且不甚直观。

另一种方法,是使用像这样的函数链。代码如下:

const text = "Hello World"
text.listen().exclaim().uppercase()


这解决了嵌套函数的很多问题。传递的参数位于开头,每个函数按照其应用的顺序出现,因此listen()首先应用,执行exclaim()后再uppercase()。

不幸的是,这个例子不起作用,因为 listen和exclaim函数uppercase不是该类的方法String。它们可以通过修补类来添加String,但这作为一种技术通常并不受欢迎。

这意味着,虽然链接看起来比函数嵌套好得多,但它实际上只能与内置函数一起使用(就像数组方法经常使用的那样)。

管道结合了链接的易用性,并且能够将其与任何函数一起使用。根据当前的提案,上面的示例将如下所示:

text |> listen(%) |> exclaim(%) |> uppercase(%)

%是一个占位符,用于表示前一个函数的输出值,尽管该%字符很可能在正式版本中被其它字符替换。这允许在管道中使用接受多个参数的函数。

管道结合了链接的便利性,但可以与你编写的任何自定义函数一起使用。唯一的条件是你需要确保一个函数的输出类型与链中下一个函数的输入类型匹配。

管道传输最适合只接受从任何先前函数的返回值,管道传输的单个参数的柯里化函数。它使函数式编程变得更加容易,因为小型的构建块函数可以链接在一起以形成更复杂的复合函数。它还使得部分应用更加容易实现。

尽管很受欢迎,但管道操作符一直在努力推进该过程的第二阶段。这是由于对如何表达符号的分歧以及对内存性能及其如何与await配合。

不过,ES委员会似乎正在慢慢达成某种协议,因此希望管道操作符能够迅速完成各个阶段,并在今年露面。

值得庆幸的是,管道运算符已经在 Babel 7.15 版本中实现了。

就我个人而言,我们希望管道运算符能够在今年实现并推出,因为它将真正有助于提高 JavaScript 作为一种严肃的函数式编程语言的资格。

Record和元组

Record和 Tuple 提案目标在将不可变的数据结构引入到 JavaScript中。

元组类似于数组(值的有序列表),但是它们的深度是不可变的。这意味着元组中的每个值必须是原始值或另一个Record或元组(不是数组或对象,因为它们在 JavaScript 中是可变的)。

元组的创建方式与数组文字类似,但#前面有一个前导哈希符号 (#):

const heroes = #["Batman", "Superman", "Wonder Woman"]


元组一旦创建,就不能添加其他值,也不能删除任何值,这些值也无法被更改。

Record类似于对象(键值对的集合),但它们也是深度不可变的。它们的创建方式与对象类似,与元组基本相同,它们均以前导哈希开头:

const traitors = #{
diane: false,
paul: true,
zac: false,
harry: true
}


Record 将使用点符号来访问属性和方法:

traitors.paul
<< true


数组使用的方括号表示法,也可以用在元组上:

heroes[1]
<< "Superman"


但由于它们是不可变的,因此你无法更新任何属性:

traitors.paul = false
<< Error


heroes[1] = "Supergirl"
<< Error


元组和记录的不变性,意味着你将能够使用===运算符轻松地比较它们:

heroes === #["Batman", "Superman", "Wonder Woman"];
<< true

需要注意的一件事是,在考虑记录的相等性时,属性的顺序并不是那么重要:

traitors === #{
ross: false,
zac: false,
paul: true,
harry: true
};
// still true, even though the order of people has changed
<< true


不过,顺序对于元组来说,是很重要的属性,这是因为它们是有序的数据列表:

heroes === #["Wonder Woman", "Batman", "Superman"];
<< false


下面的页面有一个带有现场游乐场的实用教程,因此,你可以习惯记录和元组的工作方式。

https://tc39.es/proposal-record-tuple/tutorial/


正则表达式 /v 标志

从版本 3 开始,正则表达式就被纳入 JavaScript 中,并且自那时以来已经有了许多改进(例如uES2015 中使用标志的 Unicode 支持)。

标志v 提案旨在完成u标志所做的所有事情,但它增加了一些额外的好处,我们将在下面的示例中看到。

简单地说,实现该v标志需要/v在正则表达式的末尾添加 a 。

例如,可以使用以下代码来测试某个字符是否为表情符号:

const isEmoji = /^\p{RGI_Emoji}$/v;
isEmoji.test("💚");
<< true
isEmoji.test("🐨");
<< true


这将使用RGI_Emoji模式来识别表情符号。

该v标志还允许你在正则表达式中使用设置表示法。例如,你可以使用--运算符从一种模式中减去另一种模式。

以下代码可用于从表情符号集中删除任意的“爱心”符号:

const isNotHeartEmoji = /^[\p{RGI_Emoji_Tag_Sequence}--\q{💜💚♥️💙🖤💛🧡🤍🤎}]$/v;
isNotHeartEmoji.test("💚");
<< false
isNotHeartEmoji.test("🐨");
<< true


你可以使用找到两个模式的交集&&。例如,以下代码将查找希腊符号和字母的交集:

const GreekLetters = /[\p{Script_Extensions=Greek}&&\p{Letter}]/v;
GreekLetters.test('π');
<< true
GreekLetters.test('𐆊');
<< false

该v标志还解决了该u标志不区分大小写的一些问题,使其成为在几乎所有情况下使用的更好选择。

正则表达式标志v在 2023 年已经达到了第 4 阶段,并已在所有主流浏览器中实现,因此它完全有望成为 ES2024 规范中的一部分。

Decorator装饰器

Decorator的提案旨在使用装饰器来原生扩展 JavaScript 类。

装饰器在许多面向对象语言(例如 Python语言)中已经很常见,并且已经包含在 TypeScript 中。它们是标准的元编程抽象,允许你向函数或类添加额外的功能,而无需更改其结构。例如,你可能想向方法添加一些额外的验证,可以通过创建一个验证装饰器来检查输入到表单中的数据来完成此操作。

虽然 JavaScript 允许你使用函数来实现这种设计模式,但大多数面向对象的程序员更喜欢一种更简单、更原生的方式来实现这一点,只是为了让生活变得更轻松。

该提案添加了一些语法糖,使你可以轻松地在类中实现装饰器,而不必考虑绑定this到类。它提供了一种更简洁的方式来扩展类元素,例如类字段、类方法或类访问器,甚至可以应用于整个类。

装饰器通过符号的前缀进行标识@,并且始终紧邻放置在它们要“装饰”的代码之前。

例如,类装饰器将紧接在类定义之前。在下面的示例中,validation装饰器应用于整个类FormComponent:

@validation
class FormComponent {
// code here
}


// The decorator function also needs defining
function validation(target) {
// validation code here
}


类方法装饰器紧接在它所装饰的方法之前。在下面的示例中,validation装饰器应用于该submit方法:

class FormComponent {
// class code here


@validation
submit(data) {
// method code here
}
}


// The decorator function also needs defining
function validation(target) {
// validation code here
}


装饰器函数定义接受两个参数:值与上下文。

value 参数指的是被修饰的值(例如类方法),上下文包含有关该值的元数据,例如它是否是函数、它的名称以及它是静态的还是私有的。你还可以将初始化函数添加到上下文中,该函数将在实例化类时运行。

Decorator 提案目前处于第 3 阶段,并已在 Babel 中实现,因此,各位开发者已经能够尝试这些新语法。

结论

各位同学,以上和大家分享了这5个令人兴奋的JavaScript新特性。

这些功能都将为 JavaScript 带来巨大的补充,所以让我们祈祷它们能在今年实现这一宏伟目标!

各位怎么看?你希望今年的规范中添加哪些内容?欢迎补充!~

作者:校长

参考:

https://www.sitepoint.com/new-javascript-ecmascript/

评论