ECMA 与 JavaScript 有啥关系
首先来说说 ECMA
是一个什么样的组织
ECMA 成立于 1961 年,最初是由欧洲的一些计算机制造商联合发起成立的,旨在促进计算机技术在欧洲的发展和标准化。也就是说 ECMA 的成立就是为了通过制定统一的标准,提高计算机系统的兼容性和互操作性。
其中 ECMA - 262
是 JavaScript
语言的核心规范。 最近十年一般都是每隔一年更新一次规范和语法,所以也就是我们所谓的 es2022、es2023、es2024
等。
除了 ECMAScript
,ECMA
还制定了其他一些重要标准,如 ECMA - 334(C# 语言规范)
、ECMA - 335(Common Language Infrastructure,CLI)
等。
ECMAScript 最新的语法与草案在哪儿看:
其实很简单, 直接去他们的官网即可 ecma-international.org/publication...
上面图面可以明确看出, 我们最新的 应该是 es2024 , 由 24 年 5 月份定稿
可以看到已经更新到 15 个确定版本。 上面的站点链接可以直接去下载历史版本的所有确认的版本文档。 非常详细。
ECMA - 262 规范与语法的定稿
如何定稿
这个也是我非常想给大家聊一聊的话题。 也就是说, 每年 ECMAScript 的新语法新规范是怎么来的?
实际上是每年全世界各地的开发人员, 都可以向 ECMA 组织提供他们的提案, 然后由组织人员来筛选, 经过以下几个阶段, 就可以定稿是否该提案被采用:
阶段名称 | 描述 |
---|---|
Stage 0 Proposals | 提案的最初始阶段,只是初步概念,未经过详细设计和论证,可能只是一个简单描述或讨论主题,没有完整提案文档,也未进行技术评估或可行性分析 |
Stage 1 Proposals | 当 Stage 0 的想法得到关注后进入此阶段,提案会被细化,形成相对完整的提案文档,包括新特性的语法示例、语义解释、使用场景、兼容性分析等,但还未经过技术委员会深入评审 |
Active Proposals | 已经通过 Stage 1,进入更深入的讨论和完善过程,在社区和技术委员会中引发积极讨论,不断吸收反馈来完善自身,处于活跃的修改状态 |
Finished Proposals | 完成了所有必要的讨论、修改和验证工作,被认为成熟可纳入标准,通过技术委员会评审且在社区得到广泛认可,等待合适时机纳入语言标准文档 |
Inactive Proposals | 由于各种原因(如技术不可行、与语言方向不符、缺乏社区支持等)没有继续推进,可能被搁置或废弃,不再进行开发和完善,除非有特殊情况 |
来源请参考:github.com/tc39/ecma26...
最后到了 Finished Proposals
才会认为是成熟可靠的提案, 很大概率会出现在 ES2025 的定稿语法规范里面。
所以此次我们要聊的, 就是 Finished Proposals
已经确定的语法。
ES2025 已经定稿语法有哪些
首先我们知道哪儿去找 ES2025 草案已经定稿的规范?
这儿有两个站点推荐:
- 最新的草案汇总站点 tc39.es/ecma262/
可以明确看到, 它就是 2025 的草案文档, 最近编辑时间是 2024 年 10 月 4 日。
但是这个文章非常的长, 转为 PDF 有六百多页, 纯英文, 而且有非常多的专业词汇, 以及很多草案汇总, 所以要确定哪些是最终定稿草案还是很麻烦的。
- ecma-262 github 官方仓库: github.com/tc39/ecma26...
建议直接访问这个官方仓库, 他对草案的各个阶段进行了分类, 就很容易找到我们想要的定稿提案了。
进去之后, 发现 2025 只有两个语法是明确的定稿提案
定稿语法规范详解
proposal-set-methods
这是一项关于向 JavaScript 内置类添加联合和交集等方法的提议
Set
。
提议
这将添加以下方法:
Set.prototype.intersection(other)
Set.prototype.union(other)
Set.prototype.difference(other)
Set.prototype.symmetricDifference(other)
Set.prototype.isSubsetOf(other)
Set.prototype.isSupersetOf(other)
Set.prototype.isDisjointFrom(other)
这些方法都要求它们的参数是一个集合,或者至少在具有数字size
属性和方法方面看起来像集合的东西。
Set.prototype.intersection(other)
获取交集, 返回结果为 交集结果
js
const set1 = new Set([1, 2]);
const set2 = new Set([2, 3]);
const result = set1.intersection(set2);
console.log('result', result);
// 数据结果为是否拥有交集
Set.prototype.union(other)
获取 set 的并集, 返回为并集结果
js
let set1 = new Set( [ 1 , 2 ] );
let set2 = new Set( [ 2 , 3 ] );
const res = set1.union(set2);
console.log(res);
// 输出结果:Set(3) {1, 2, 3}
Set.prototype.difference(other)
前面两个应该是比较好理解的。 但是 差集 就并不是很好理解了。 我们可以看看下面这个图
差集就像 sql 的LEFT JOIN
。 本质就是先取 A 的全集, 然后减去 B 中的部分。
代码可以参考:
js
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const onlyFrontEnd = frontEndLanguages.difference(backEndLanguages);
// => Set {"HTML", "CSS"}
const onlyBackEnd = backEndLanguages.difference(frontEndLanguages);
// => Set {"Python", "Java"}
Set.prototype.symmetricDifference(other)
symmetricDifference
就更加不好理解了,还是给一个图。 本质就是排除 A 和 B 交集的部分。
就像 FULL OUTER JOIN 排除两个表中的任何元素。
语法举例
js
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const onlyFrontEnd = frontEndLanguages.symmetricDifference(backEndLanguages);
// => Set {"HTML", "CSS", "Python", "Java"}
const onlyBackEnd = backEndLanguages.symmetricDifference(frontEndLanguages);
// => Set {"Python", "Java", "HTML", "CSS"}
Set.prototype.isSubsetOf(other)
这个就比较好理解了。 简而言之, 判断是否 B 是否为 A 的子集。
js
const A = new Set(["JavaScript", "HTML", "CSS"]);
const B = new Set(["HTML", "CSS"]);
B.isSubsetOf(A);
// => true
A.isSubsetOf(B);
// => false
Set.prototype.isSupersetOf(other)
如果一个集合中的所有元素都出现在第一个集合中,则第二个集合是另一个集合的超集。这与子集的关系相反。
js
const A = new Set(["JavaScript", "HTML", "CSS"]);
const B = new Set(["HTML", "CSS"]);
B.isSupersetOf(A);
// => false
A.isSupersetOf(B);
// => true
Set.prototype.isDisjointFrom(other)
如果一个集合与另一个集合没有共同的元素,那么它们就是不相交的。
js
const A = new Set(["JavaScript", "HTML", "CSS"]);
const B = new Set(["JavaScript", "Ruby", "Python"]);
const C = new Set(["Java", "C++", "TypeScript"]);
B.isDisjointFrom(C);
// => true - 没有交集元素
A.isDisjointFrom(B);
// => false - 有交集元素 JavaScript
proposal-duplicate-named-capturing-groups
这个是说的正则语法里面支持「捕获组」
目前,在 JavaScript 中,正则表达式中命名的捕获组必须是唯一的。因此
scss
str.match(/(?<year>[0-9]{4})-[0-9]{2}|[0-9]{2}-(?<year>[0-9]{4})/)
是错误,因为您重复使用了year
组名。但有时您想匹配可以以多种格式编写的内容(如上所示)。在这种情况下,如果能够使用相同的组名就好了。
所以为了解决上面的问题, 才了有此提案
提议
1. 重复的名称必须有不同的替代方案
目前,此提案仅允许您在名称出现在不同的|
替代方案中时重复使用名称,因此单个匹配不可能实际多次使用相同的名称。如果您有在单个替代方案中重复使用名称的用例,请打开问题。请注意,这会使语义变得更加复杂。
2. 反向引用
通过这种改变,可以有一个指向多个不同组的反向引用,例如
xml
/(?:(?<a>x)|(?<a>y))\k<a>/
然而,上述限制意味着最多只有一个组可以真正参加比赛。*
因此最多只有一个会真正匹配。该提案表示反向引用指的是实际参与的那个。如果没有匹配,它会无条件匹配而不消耗任何输入(这已经是它的工作原理)。
*从技术上讲,不同的组可以参与重复的不同迭代(+
、、等),但已经确定只有最后一次迭代才"计数"以用于反向引用。*``{2}
3. 对象groups
与反向引用一样,比赛结果上对象的相应命名属性groups
指的是实际参与比赛的组。
为了属性枚举顺序的目的,这些命名属性按照它们在正则表达式中出现的顺序创建,而不管哪些组实际参与了匹配。
补充:您能以不同的方式「引用一个组吗」?
考虑
css
/(?<a>x)|\k<a>/
反向引用永远没有用,因为它引用的组处于不同的替代方案中。因此,它的行为是始终匹配而不消耗任何输入。(这很奇怪,但也是它对\1
-style 匹配的工作方式。)即使有重复也是如此,因为在每次迭代开始时,重复部分内的捕获组都会被清除。因此,没有理由写这个。
不幸的是,目前这是合法的。该提案不会改变这一点。