Stage 0 → Stage 1
从 Stage 0 进入到 Stage 1 有以下门槛:
- 找到一个 TC39 成员作为 champion 负责这个提案的演进;
- 明确提案需要解决的问题与需求和大致的解决方案;
- 有问题、解决方案的例子;
- 对 API 形式、关键算法、语义、实现风险等有讨论、分析。
Stage 1 的提案会有可预见的比较大的改动,以下列出的例子并不代表提案最终会是例子中的语法、语义。
Reversible String Split
提案链接:https://github.com/tc39/proposal-reversible-string-split
JavaScript中的 split 方法能够基于指定的分隔符来拆分一个字符串,并将每次拆分的子项保存在一个数组中返回,它接收两个参数:
- separator,即用于拆分的分隔符,可以是字符串或正则表达式。
- limit,返回的拆分结果数组的长度,或者也可以理解为进行拆分的次数。
需要注意的是,当你指定了 limit 参数,split 方法的返回值并不会包含由于达到上限而停止拆分的剩余部分,如上面的例子中,剩余的字符串被直接抛弃了:
const str = 'a|b|c|d|e'; // ["a", "b"], 字符串的剩余部分被抛弃了 console.log(str.split("|",2))
这即是此提案所关注的核心问题,因为在其他主流语言中,字符串的 split 方法都将在达到拆分上限时返回余下的部分,如:
Java 代码:
class Playground { public static void main(String[] args) { String s = new String("a|b|c|d|e|f"); for(String val : s.split("\\|", 2)) { System.out.println(val); } } } // a // b|c|d|e|f
Rust 代码:
fn main() { let v = "a|b|c|d|e|f".splitn(2, "|").collect::<Vec<_>>(); println!("{:?}", v); } // ["a", "b|c|d|e|f"]
Go 代码:
package main import ( "fmt" "strings" ) func main() { fmt.Printf("%#v", strings.SplitN("a|b|c|d|e|f", "|", 2)) } // []string{"a", "b|c|d|e|f"}
以及 Python 代码:
print('a|b|c|d|e|f'.split('|', 2)) # ['a', 'b', 'c|d|e|f']
可以看到,Java、Rust、Go、Python 中的 split 方法都会在拆分次数达到 limit 后,返回余下的部分。虽然这里 Python 与其他语言也存在着不同,它会进行 N 次拆分,返回一个 N + 1 长度的数组,而其他语言认为 N 直接代表着返回值数组的长度,因此进行 N - 1 次拆分,返回一个 N 长度的数组。
这些语言和 JavaScript 的 split 方法有一个很明显的区别,即它们的 split 方法返回值由于包含了剩余部分,所以能再次通过 join 方法拼接得到原本的字符串(即 reversible),而 JavaScript 则做不到。这一反转过程可以用以下的伪代码表示:
join(Separator, Value.split(Separator, Limit)) == Value;
为了解决这一问题,同时不影响现有的 split 方法的表现,此提案提出新增一个 splitN 方法,其表现与 Java、Go 语言一致,进行 N - 1次拆分,返回一个长度为 N 的数组,包含字符串的余下部分。
console.log("a|b|c|d|e|f".splitN("|", 2)); // ["a", "b|c|d|e|f"]
而关于为何 JavaScript 的 split 方法会有着如此的表现,作者也在最后提到原因已经无可追溯,能查证的资料表明 split 方法的第二个参数最初是在 1997 年的 Netscape Navigator 4 浏览器中首次支持,而在 ECMA262 中首次明确的记录版本是在 ES3。
结语
由贺师俊牵头,阿里巴巴前端标准化小组等多方参与组建的 JavaScript 中文兴趣小组(JSCIG,JavaScript Chinese Interest Group)在 GitHub 上开放讨论各种 ECMAScript 的问题,非常欢迎有兴趣的同学参与讨论:https://github.com/JSCIG/es-discuss/discussions 。