javascript Array对象
数组是一段线性分配的内存,它通过整数去计算偏移并访问其中的元素。数组是很快的数据结构,但不幸的是,Javascript并没有像这种数组一样的数据结构。Javascript的数组实质是对象,它把数组的下标转换成字符串,用其作为属性,因此它明显比真正的数组慢,但它可以更方便地使用。
改变自身pop,push,reverse,shift,sort,splice,unshift, 不改变自身concat,join,slice,indexOf,lastIndexOf(后两个为1.6),1.6新增的迭代器:map,filter,forEach,every,some,1.8新增reduce,reduceRight
Array 对象的方法
FF: Firefox, N: Netscape, IE: Internet Explorer
方法 | 描述 | FF | N | IE |
---|---|---|---|---|
concat() | 方法concat()将创建并返回一个新数组,这个数组是将所有参数都添加到array中生成的。它并不修改array。如果要进行concat()操作的参数是一个数组,那么添加的是数组中的元素,而不是数组。
var a = [1,2,3]; a.concat(4, 5); // Returns [1,2,3,4,5] a.concat([4,5]); // Returns [1,2,3,4,5] a.concat([4,5], [6,7]); // Returns [1,2,3,4,5,6,7] a.concat(4,[5, [6,7]]); // Returns [1,2,3,4,5,[6,7]] |
1 | 4 | 4 |
join() | 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。 | 1 | 3 | 4 |
pop() | 删除并返回数组的最后一个元素 | 1 | 4 | 5.5 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度。 | 1 | 4 | 5.5 |
reverse() | 颠倒数组中元素的顺序。 | 1 | 3 | 4 |
shift() | 删除并返回数组的第一个元素 | 1 | 4 | 5.5 |
slice() | 从某个已有的数组返回选定的元素 | 1 | 4 | 4 |
sort() | 对数组的元素进行排序,有一个可选参数,为比较函数。 | 1 | 3 | 4 |
splice() | 删除元素,并向数组添加新元素。 | 1 | 4 | 5.5 |
toSource() | 代表对象的源代码 | 1 | 4 | - |
toString() | 把数组转换为字符串,并返回结果。 | 1 | 3 | 4 |
toLocaleString() | 把数组转换为本地数组,并返回结果。 | 1 | 3 | 4 |
unshift() | 向数组的开头添加一个或更多元素,并返回新的长度。 | 1 | 4 | 6 |
valueOf() | 返回数组对象的原始值 | 1 | 2 | 4 |
Array 对象的属性
方法 | 描述 | FF | N | IE |
---|---|---|---|---|
index | 1 | 3 | 4 | |
input | 在普通的Array中是不具备input属性的,只有在调用String对象的match()方法后返回的数组才具有input属性。它是用来存放匹配前的原字符串的内容。 | 1 | 3 | 4 |
length | 设置或返回数组中元素的数目。 | 1 | 2 | 4 |

我们先来看数组克隆,现在公认用concat()来克隆数组的速度最快。下面做一些测试,分别为直接遍历复制,array.slice(0)与array.concat()
判断一个变量引用的对象是否为数组。
var isArray = function (a){ return a && typeof a === 'object' && typeof a.length === 'number' && typeof a.splice === 'function' && !(a.propertyIsEnumerable( 'length' )); } |
让数组具有计算能力,这个也很常用,不要用于财会的特殊报表中。
Function.prototype.method = function (name,func){ this .prototype[name] = func; return this ; } Array.method( 'reduce' , function (fn,value){ for ( var i=0,l= this .length;i<l;i++){ value = fn( this [i],value); } return value; }); |
如何使用,我们可以创建一个数字数组与相关的四则运算函数,把它们代入reduce函数中就行了
var data = [4,8,10,12,16] var add = function (a,b){ return a+b; } var mult = function (a,b){ return a*b; } //使用 var sum = data.reduce(add,0) var product = data.reduce(mult,1); |
each方法,让元素逐个执行传入的方法。JavaScript 1.6里已经实现了相应的forEach方法,但IE不支持,人们搞了个相近的each方法,在各大类库都有相应的实现。我们看一个漂亮的实现(作者为51JS的客服果果):
Array.prototype.each = function (fn){ for ( var i=0;i < this .length;i++) this [i].constructor==Array? this [i].each(fn): fn.call( this [i],i); }; [1,[2,[3,[4,[5,[6,[7,[8,[9,[0]]]]]]]]]].each( function (){ return alert( this ); }); |
上面这个比较强大,除了能深层遍历数组外,还能遍历类数组对象(如arguments,NodeList),对象的所有属性都会被fn方法进行调用。但是从设计模式来看,它承担职责太多了.each方法就应该是面向数组,如果是对象或类数组对象,我们应该将它们转化为数组,如JQuery的makeArray,mootools和Prototype的$A。
var arrayize = function (iterable){ try { return Array.prototype.slice.call(iterable); } catch (e){ var l = iterable.length || 0, array = new Array(l); while (l--) array[l] = iterable[l]; return array; } } |
接着下来我们就可以实现纯数组的each函数了。
var each = function (func, array) { for ( var i=0,l = array.length; i<l; ++i) { func(array[i]) } } |
然后再改成一个原型方法
Array.prototype.each = function (func) { each(func, this ); }; |
不过,如果浏览器支持javascript1.6的forEach方法,就用forEach
Array.prototype.each = function (func) { if (Array.prototype.forEach){ this .forEach(func); } else { each(func, this ); } }; |
用法:
[4, 5, 6].each( function (index) { alert(index + "+2 = " + (index+2)); }) |
火狐官网还有一个实现:
if (!Array.prototype.forEach) { Array.prototype.forEach = 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 ); } }; } |
让我们看一下jQuery提供的each方法的具体实现
jQuery.each(obj,fn,arg)
该方法有三个参数:进行操作的对象obj,进行操作的函数fn,函数的参数args。
让我们根据ojb对象进行讨论:
1.obj对象是数组
each方法会对数组中子元素的逐个进行fn函数调用,直至调用某个子元素返回的结果为false为止,也就是说,我们可以在提供的fn函数进行处理,使之满足一定条件后就退出each方法调用。当each方法提供了arg参数时,fn函数调用传入的参数为arg,否则为:子元素索引,子元素本身。
2.obj 对象不是数组
该方法同1的最大区别是:fn方法会被逐次不考虑返回值的进行进行。换句话说,obj对象的所有属性都会被fn方法进行调用,即使fn函数返回false。调用传入的参数同1类似。
jQuery.each= function ( obj, fn, args ) { if ( args ) { if ( obj.length == undefined ){ for ( var i in obj ) fn.apply( obj, args ); } else { for ( var i = 0, ol = obj.length; i < ol; i++ ) { if ( fn.apply( obj, args ) === false ) break ; } } } else { if ( obj.length == undefined ) { for ( var i in obj ) fn.call( obj, i, obj ); } else { for ( var i = 0, ol = obj.length, val = obj[0]; i < ol && fn.call(val,i,val) !== false ; val = obj[++i] ){} } } return obj; } |
需要特别注意的是each方法中fn的具体调用方法并不是采用简单的fn(i,val)或fn(args),而是采用了fn.call(val,i,val)或fn.apply(obj.args)的形式,这意味着,在你自己的fn的实现中,可以直接采用this指针引用数组或是对象的子元素。这种方式是绝大多数jQuery所采用的一种实现方式。
Array.prototype.contains = function (obj) { return this .indexOf(obj) != -1; }; Array.prototype.copy = function (obj) { return this .concat(); }; Array.prototype.insertAt = function (obj, i) { this .splice(i, 0, obj); }; Array.prototype.insertBefore = function (obj, obj2) { var i = this .indexOf(obj2); if (i == -1) this .push(obj); else this .splice(i, 0, obj); }; Array.prototype.removeAt = function (i) { this .splice(i, 1); }; Array.prototype.remove = function (obj) { var i = this .indexOf(obj); if (i != -1) this .splice(i, 1); }; |
//数组去重 //2010.12.22 function uniq1(array) { var n = array.length; for ( var i = 0; i < n - 1; i++) for ( var j = i + 1; j < n;) if (array[i] === array[j]) { array.splice(j, 1); n--; } else { j++; } return array; } function uniq2(array) { var result = [], k = 0,n = array.length; for ( var i = 0; i < n; i++) { for ( var j = i + 1; j < n; j++) if (array[i] === array[j]) j = ++i; result[k++] = array[i]; } return result; } |
//逐个移除数组里的元素 var array = [ "a" , "b" , "c" , "d" ]; for ( var i=0;i < array.length;i++){ array.splice(i--,1); } alert(array) |
相关链接:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义