JavaScript 数组:对比 slice 与 splice
对于 JavaScript 语言来讲,入门者甚至是专家都会经常搞不清 slice
和 splice
这两个方法。它们虽然名称相似,但是功能却完全不同。在使用中,可以通过选择一个具有强语义表达性的 API 来减少混淆的发生。
数组的 slice
(ECMAScript 5.1 标准 15.4.4.10 节)非常类似于字符串的 slice
。根据规范,slice
需要两个参数,_起点_和_终点_。它会返回一个包含了从起点开始,到终点之前之间所有元素的新数组。理解 slice 的功能并不是太难:
'abc'.slice(1,2) // "b"
[14, 3, 77].slice(1, 2) // [3]
需要特别注意的是它并不会修改原数组。下面的代码段描述了这个行为,_x_ 的值没有变,_y_ 则是被截取的部分。
var x = [14, 3, 77];
var y = x.slice(1, 2);
console.log(x); // [14, 3, 77]
console.log(y); // [3]
虽然 splice
(15.4.4.12 节)也需要(至少)两个参数,但它的意义则完全不同。
[14, 3, 77].slice(1, 2) // [3]
[14, 3, 77].splice(1, 2) // [3, 77]
除此之外,splice
还会改变原数组。不要太惊讶,这正是 splice 的本意。
var x = [14, 3, 77]
var y = x.splice(1, 2)
console.log(x) // [14]
console.log(y) // [3, 77]
当你编写自己的模块时,选择一个最不容易发生混淆的 API 非常重要。理论上,你的用户不应该总是通过阅读文档来判断他们需要哪一个。那么我们应该遵循哪种命名规范呢?
我最熟悉的规范(与我之前在 QT 上的经验有关)是正确地选择动词:现在时表示可能的修改行为,过去时则不会修改原对象,而是返回一个新的版本。如果可以的话,这两种版本都要提供。参考下面的例子:
var p = new Point(100, 75);
p.translate(25, 25);
console.log(p); // { x: 125, y: 100 }
var q = new Point(200, 100);
var s = q.translated(10, 50);
console.log(q); // { x: 200, y: 100 }
console.log(s); // { x: 210, y: 150 }
注意(在二维笛卡尔坐标系中)移动位置的 translate()
和仅创建一个移动过的坐标的 translated()
之间的区别。调用 translate
会修改点 p 的值。然而,因为 translated()
不修改原对象,对象 q 没有被修改,而只返回了一个新的拷贝 _s_。
如果这个规范能够非常一致地部署到你的应用中,那么上面提到的那种混淆则会被最大化地减低。有一天,你会让你的用户高兴地喊出_我终于明白了_!