yanni4night

JavaScript 数组:对比 slice 与 splice

yanni4night · 2016-08-12翻译 · 1726阅读 原文链接

对于 JavaScript 语言来讲,入门者甚至是专家都会经常搞不清 slicesplice 这两个方法。它们虽然名称相似,但是功能却完全不同。在使用中,可以通过选择一个具有强语义表达性的 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]

虽然 splice15.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

如果这个规范能够非常一致地部署到你的应用中,那么上面提到的那种混淆则会被最大化地减低。有一天,你会让你的用户高兴地喊出我终于明白了

相关文章