JavaScript Array数组对象扩展函数详解与实现

作者:拾光

时间:2026-10-25

浏览:75

本文深入探讨JavaScript中Array对象的扩展机制,对比直接在Array.prototype上扩展与封装YArray工具函数的两种方案。详细解析了YUI库中each、hash、indexOf、numericSort、some等核心方法的实现逻辑,并对照JavaScript 1.6-1.8标准,逐一讲解every、filter、map、reduce、reduceRight等原生扩展方法的原理与代码实现,帮助开发者理解数组操作底层原理。

文章目录

Array对象扩展概述

本文重点介绍如何对JavaScript中的Array对象进行功能扩展。



主要有两种扩展方式:第一种是直接修改Array.prototype原型;第二种是通过自定义工具函数(如YUI中的YArray)对数组对象进行封装扩展。



第二种方式,即使用自定义方法对数组对象进行扩展。



需要注意的是,直接在Array.prototype上扩展方法时,不能直接应用于DOM对象,例如通过document.getElementsByTagName('div')获取的nodeList对象无法直接使用这些扩展方法。



对于追求代码纯净性的开发者而言,直接修改原生原型可能会破坏原始生态环境。



YUI数组工具函数实现

接下来,我们参考YUI库中操作数组的一些方法,对其源码进行简单剥离并稍作修改。



具体代码如下:

 
(function(){
var YArray;
YArray = function(o,idx,arraylike){
var t = (arraylike) ? 2 : YArray.test(o),
l, a, start = idx || 0;
if (t) {
try {
return Array.prototype.slice.call(o, start); //借助Array原生方法来把aguments转换为JS数组
} catch(e) {
a = [];
l = o.length;
for (; start<l; start++) {
a.push(o[start]);
} 
return a;
} 
} else {
return [o];
} 
} 
YArray.test = function(o){
var r = 0;
if (o && (typeof o == 'object' ||typeof o == 'function')) {
if (Object.prototype.toString.call(o) === "[object Array]") {
r = 1;
} else {
try {
if (('length' in o) && !o.tagName && !o.alert && !o.apply) {
r = 2;
} 
} catch(e) {}
} 
} 
return r;
} 
YArray.each = (Array.prototype.forEach) ? //先检测浏览器是否已支持,若有则调用原生
function (a, f, o) {
Array.prototype.forEach.call(a || [], f, o || Y);
return YArray;
} : 
function (a, f, o) {
var l = (a && a.length) || 0, i;
for (i = 0; i < l; i=i+1) {
f.call(o || Y, a[i], i, a);
} 
return YArray;
}; 
YArray.hash = function(k, v) {
var o = {}, l = k.length, vl = v && v.length, i;
for (i=0; i<l; i=i+1) {
if (k[i]) {
o[k[i]] = (vl && vl > i) ? v[i] : true;
} 
} 
return o;
}; 
YArray.indexOf = (Array.prototype.indexOf) ?
function(a, val) {
return Array.prototype.indexOf.call(a, val);
} : 
function(a, val) {
for (var i=0; i<a.length; i=i+1) {
if (a[i] === val) {
return i;
} 
} 
return -1; //寻找不到的情况
}; 
YArray.numericSort = function(a, b) {
return (a - b); //从小到大排序, return (b - a); 从大到小
}; 
YArray.some = (Array.prototype.some) ?
function (a, f, o) {
return Array.prototype.some.call(a, f, o);
} : 
function (a, f, o) {
var l = a.length, i;
for (i=0; i<l; i=i+1) {
if (f.call(o, a[i], i, a)) {
return true;
} 
} 
return false;
}; 
})(); 


借助Array原生方法来把aguments转换为JS数组的其他方法 (Dom对象不可以,只有遍历)


具体实现代码如下:

 
Array.apply(null,arguments);
[].slice.call(arguments,0);
[].splice.call(arguments,0,arguments.length);
[].concat.apply([],arguments);
... 


YArray函数不仅可以操作数组对象,也对nodeList对象进行了兼容处理。


示例:YArray(document.getElementsByTagName("div"));


通过遍历DOM对象,将其重新组装成一个标准数组。


相关代码如下:

 
a = [];
l = o.length;
for (; start<l; start++) {
a.push(o[start]);
} 
return a;

YArray.each


用于遍历数组,如果传入了回调函数,每次遍历时都会执行该callback。


使用示例代码如下:

 
YArray.each([1,2,3],function(item){
alert(item);// 执行了3次,1,2,3
}); 

YArray.hash


将两个数组组装成键值对,可以理解为一个JSON对象。


示例:YArray.hash(["a","b"],[1,2]);



YArray.indexOf


返回与指定值相等的元素在数组中的索引值。



示例:YArray.indexOf([1,2],1)


YArray.numericSort


对数组进行数值排序,默认为从小到大。


示例:[3, 1, 2].sort(YArray.numericSort);


YArray.some


判断数组中是否有元素通过了回调函数的处理,如果有,则立即返回true;如果都没有,则返回false。


使用示例代码如下:

 
YArray.some([3, 1, 2],function(el){
return el < 4;
}) 


JavaScript原生数组扩展方法

接下来,我们看看JavaScript 1.6至1.8版本对数组的扩展,并学习如何实现相同的功能。


every


filter


forEach


indexOf


lastIndexOf


map


some


reduce


reduceRight



Array.prototype.every


具体实现代码如下:

 
if (!Array.prototype.every)
{ 
Array.prototype.every = function(fun /*, thisp*/)
{ 
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{ 
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
} 
return true;
}; 
} 

该方法用于判断数组中的每个元素是否都通过了回调函数的处理,如果是,则返回true;如果有一个不是,则立即返回false。


这与我们之前提到的YUI中的some函数很类似,但功能刚好相反。



Array.prototype.filter


具体实现代码如下:

 
Array.prototype.filter = function (block /*, thisp */) { //过滤器 ,添加方便,进行判断过滤
var values = [];
var thisp = arguments[1];
for (var i = 0; i < this.length; i++)
if (block.call(thisp, this[i]))
values.push(this[i]);
return values;
}; 

使用方法示例:


具体代码如下:

 
var val= numbers.filter(function(t){
return t < 5 ;
}) 
alert(val);

forEach、indexOf和some的实现可以参考上述YUI代码,此处不再赘述。


lastIndexOf与indexOf代码相似,只是遍历方向是从后往前。



下面讲解‘map’方法。


具体实现代码如下:

 
Array.prototype.map = function(fun /*, thisp*/) {
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = new Array(len);
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this)
res[i] = fun.call(thisp, this[i], i, this);
} 
return res;
}; 

该方法用于遍历数组并执行函数,迭代数组中的每个元素作为参数执行callback方法,由callback方法对每个元素进行处理,最后返回处理后的新数组。


示例:var numbers = [1, 4, 9];


var roots = numbers.map(function(a){return a * 2});



Array.prototype.reduce


具体实现代码如下:

 
Array.prototype.reduce = function(fun /*, initial*/) {
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
if (len == 0 && arguments.length == 1)
throw new TypeError();
var i = 0;
if (arguments.length >= 2) {
var rv = arguments[1];
} else {
do {
if (i in this) {
rv = this[i++];
break;
} 
if (++i >= len)
throw new TypeError();
} while (true);
} 
for (; i < len; i++) {
if (i in this)
rv = fun.call(null, rv, this[i], i, this);
} 
return rv;
}; 

该方法让数组元素依次调用给定函数,最后返回一个累积值,因此给定函数必须包含返回值。



Array.prototype.reduceRight


顾名思义,该方法是从右往左进行归约操作。


具体实现代码如下:

 
Array.prototype.reduceRight = function(fun /*, initial*/) {
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
if (len == 0 && arguments.length == 1)
throw new TypeError();
var i = len - 1;
if (arguments.length >= 2) {
var rv = arguments[1];
} else {
do {
if (i in this) {
rv = this[i--];
break;
} 
if (--i < 0)
throw new TypeError();
} while (true);
} 
for (; i >= 0; i--) {
if (i in this)
rv = fun.call(null, rv, this[i], i, this);
} 
return rv;
}; 

除了上述方法,只要开发中需要,都可以将自定义方法添加到Array.prototype上。


例如常用的toString方法。


具体实现代码如下:

 
Array.prototype.toString = function () {
return this.join('');
}; 

还可以添加toJson、uniq、compact、reverse等实用方法。


Array扩展对前端开发还是很有帮助的。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章