Slice notation S1
中文标题:切片表示法
- 阶段: Stage 1
- 状态: 进行中
- ECMAScript 版本: —
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案为数组和类型化数组引入了切片表示法语法(例如 arr\[1:3\]),为现有的切片方法提供了更符合人体工程学且歧义更少的替代方案。该提案概述了默认边界、负索引处理和越界行为,同时明确排除了步长参数和视图等功能,以保持范围最小化。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
切片表示法
本仓库包含一个向 JavaScript 添加切片表示法语法提案。该提案目前处于 TC39 流程 的第 1 阶段。
提案发起人:
- Sathya Gunasekaran (@gsathya)
- HE Shi-Jun (@hax)
引言
切片表示法为 Array.prototype、TypedArray.prototype 等上存在的各种切片方法提供了一种符合人体工程学的替代方案。
此表示法可用于类似 Array 和 TypedArray 等原始类型的切片操作。
动机
在上面的例子中,并不清楚新创建的数组是范围 0 到 3 的切片,还是从 3 到 len(arr) 的切片。
添加第二个参数也同样有歧义,因为不清楚第二个参数是指定上界还是新切片的长度。
像 Ruby 和 C++ 这样的编程语言将新切片的长度作为第二个参数,但 JavaScript 的切片方法将上界作为第二个参数。
使用新的切片语法,可以立即明确下界是 3,上界是 len(arr)。它使意图变得明确。
该语法也比函数调用更短且更符合人体工程学。
示例
在下面的文字中,“对象的长度”指的是对象的 length 属性。
默认值
下界和上界都是可选的。
下界的默认值是 0。
上界的默认值是对象的长度。
省略所有下界和上界值,会产生对象的新副本。
负索引
如果下界为负,则起始索引计算如下:
其中 len 是对象的长度。
在上面的例子中,start = max((-2 + 4), 0) = max(2, 0) = 2。
在上面的例子中,start = max((-10 + 4), 0) = max(-6, 0) = 0。
类似地,如果上界为负,则结束索引计算如下:
这些语义与现有切片操作的行为完全匹配。
越界索引
下界和上界都被限制在对象的长度内。
这些语义与现有切片操作的行为完全匹配。
先前艺术
Python
本提案深受 Python 的启发。不出所料,Python 的切片表示法语法惊人地相似:
示例:
CoffeeScript
CoffeeScript 提供了一个 Range 运算符,该运算符对上界是 包含 的。
CoffeeScript 还提供了 Range 运算符的另一种形式,该形式对上界是 排他 的。
Go
Go 提供 切片:
还可以不提供下界或上界:
Ruby
Ruby 似乎有两种不同的方式来获取切片:
- 使用 Range:
这类似于 CoffeeScript。1..3 会生成一个 Range 对象,该对象定义了要切出的索引集合。
- 使用逗号运算符:
这里的区别在于第二个参数实际上新切片的长度,而不是上界索引。
这目前是有效的 ECMAScript 语法,这使得此方案无法继续。
常见问题解答
为什么选择 Python 语法而不是 Ruby/CoffeeScript 语法?
Python 语法排除了上界索引,这与 JavaScript 中现有的切片方法类似。
我们可以使用 CoffeeScript 的排他 Range 运算符(...),但这并不适用于所有情况,因为它与展开语法有歧义。来自 getify 的示例代码:
为什么这不使用迭代器协议?
迭代器协议不限于索引查找,这使得它与这种仅适用于索引的切片表示法不兼容。
例如,Map 和 Set 有迭代器,但我们不应该对它们进行切片,因为它们没有索引。
splice 呢?
CoffeeScript 允许在 AssignmentExpression 的左侧使用类似的语法,从而实现拼接操作。
此功能目前被省略以限制提案的范围,但可以在后续提案中纳入。
为什么这不像 Python 那样包含步长参数?
步长参数会使切片表示法与绑定运算符产生歧义。
上面是创建一个值为 [1, 3] 的新数组还是创建一个绑定方法?
这是否应该在数组上创建一个 view,而不是创建一个新数组?
Go 在底层数组上创建一个 slice,而不是分配一个新数组。
在这里,v 只是一个保存对原始数组 arr 引用的描述符。没有执行新的数组分配。更多细节请参阅 这篇博客文章。
这不对应于 JavaScript 中的任何现有构造,这将背离 JavaScript 中方法的工作方式。为了使此语法在 JavaScript 模型中良好工作,此提案中不包含这样的 view 数据结构。
切片表示法应该作用于字符串吗?
String.prototype.slice 方法对 unicode 字符处理不佳。Mathias Bynens 的 这篇博客文章 解释了这个问题。
鉴于现有方法处理不佳,此提案不会将 @@slice 添加到 String.prototype。
将其与 + 结合用于追加怎么样?
为了保持提案的范围尽可能最小,此功能未被包含在内。
运算符重载提案 可能更适合于此。
你能使用此语法创建 Range 对象吗?
切片表示法仅提供一种执行切片操作的人体工程学语法。
当前的切片表示法并不排除将来创建 range 原始类型。
这里正在讨论一个新的 Range 原始类型: https://github.com/tc39/proposal-Number.range/issues/22
这不是在进行属性查找,难道不令人困惑吗?
这实际上通过 [[Get]] 在底层对象上进行属性查找。例如,
这是对键 1 和 2 进行属性查找。
但是,它不应该查找字符串 '1:3' 吗?
不。切片表示法使其与键控查找的工作方式类似。键首先被计算为一个值,然后使用该值进行查找。
切片表示法的工作方式类似。表示法首先被计算为一个值的范围,然后查找每个值。
':' 已经有许多模式表示不同含义了。这不令人困惑吗?
根据上下文,a:b 可以表示:
LabelledStatement,其中a是标签- 对象字面量中值为 b 的属性 a:
{a: b } - ConditionalExpression:
confused ? a : b - 未来可能进入 JavaScript 的潜在类型系统(如 TypeScript 和 Flow)。
通过上下文消除这些模式之间的歧义是否开销过大?像 Python 这样的主流主流编程语言都有所有这些模式,并且被用作教学编程的主要工具。