我不认为这真的很矛盾。是的,它们可能有点令人困惑,因为 JavaScript 数组可以完成其他语言具有单独结构(列表、队列、堆栈等)的所有操作,但它们的定义在不同语言中非常一致。您可以轻松地将它们分组到您已经描述过的类别中:
- list methods:
-
push
/unshift
返回添加元素后的长度
-
pop
/shift
返回请求的元素
- 您可以定义其他方法来获取第一个和最后一个元素,但很少需要它们
-
splice
是用于在列表中间删除/替换/插入项目的通用工具 - 它返回已删除元素的数组。
-
sort
and reverse
是两种标准的就地重新排序方法。
所有其他方法都不会修改原始数组:
-
slice
按位置获取子数组,filter
通过条件和concat
与其他数组结合创建并返回新数组
-
forEach
只是迭代数组并且不返回任何内容
-
every
/some
test the items for a condition, indexOf
and lastIndexOf
搜索项目(通过相等) - 两者都返回结果
-
reduce
/reduceRight
reduce the array items to a single value and return that. Special cases are:
-
map
减少到一个新的数组 - 就像forEach
但返回结果
-
join
and toString
减少为字符串
这些方法足以满足我们的大部分需求。我们可以用它们做几乎所有的事情,而且我不知道有任何库向它们添加类似的但内部或结果方面不同的方法。大多数数据处理库(例如下划线 http://underscorejs.org/)只使它们跨浏览器安全(es5-shim https://github.com/kriskowal/es5-shim)并提供额外的实用方法。
我想要的是始终改变数组并始终返回相同的数组,这样我就可以具有某种一致性并且也能够链接。
我想说 JavaScript 的一致性是当元素或长度被修改时总是返回一个新的数组。我猜这是因为对象是引用值,更改它们常常会在引用同一数组的其他作用域中产生副作用。
链接仍然是可能的,你可以使用slice
, concat
, sort
, reverse
, filter
and map
只需一步即可一起创建一个新数组。如果您只想“修改”数组,只需将其重新分配给数组变量即可:
A = A.slice(0,1).reverse().concat(['a','b']);
突变方法对我来说只有一个优点:它们更快,因为它们可能更节省内存(当然取决于实现及其垃圾收集)。那么让我们为这些实现一些方法。作为数组子类化 http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array既不可能也没有用,我将在原生原型 http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/:
var ap = Array.prototype;
// the simple ones:
ap.each = function(){ ap.forEach.apply(this, arguments); return this; };
ap.prepend = function() { ap.unshift.apply(this, arguments); return this; };
ap.append = function() { ap.push.apply(this, arguments; return this; };
ap.reversed = function() { return ap.reverse.call(ap.slice.call(this)); };
ap.sorted = function() { return ap.sort.apply(ap.slice.call(this), arguments); };
// more complex:
ap.shorten = function(start, end) { // in-place slice
if (Object(this) !== this) throw new TypeError();
var len = this.length >>> 0;
start = start >>> 0; // actually should do isFinite, then floor towards 0
end = typeof end === 'undefined' ? len : end >>> 0; // again
start = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
end = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
ap.splice.call(this, end, len);
ap.splice.call(this, 0, start);
return this;
};
ap.restrict = function(fun) { // in-place filter
// while applying fun the array stays unmodified
var res = ap.filter.apply(this, arguments);
res.unshift(0, this.length >>> 0);
ap.splice.apply(this, res);
return this;
};
ap.transform = function(fun) { // in-place map
if (Object(this) !== this || typeof fun !== 'function') throw new TypeError();
var len = this.length >>> 0,
thisArg = arguments[1];
for (var i=0; i<len; i++)
if (i in this)
this[i] = fun.call(thisArg, this[i], i, this)
return this;
};
// possibly more
现在你可以做
A.shorten(0, 1).reverse().append('a', 'b');