数组的全面总结

数组在工作中使用频繁,但我们大多数情况下只使用到了部分特性,久而久之,对于数组其它的相关特性就变得模糊起来,不免有错漏不全的理解,这里花了一点时间,对最常用的数组做一些总结。

定义

数组的标准定义:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。
数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示。

内置方法

  • concat / slice / splice
  • sort / reverse
  • shift/ unshift
  • pop / push
  • toString
  • join

从已有的数组创建新的数组

concat / slice / splice

concat 合并两个或多个数组,返回合并结果

不改变原有数组,返回一个新的合并数组

arrayObject.concat(arrayX,arrayX,......,arrayX),
arrayX可以是值/数组对象

[1,2].concat(3,4); //[1, 2, 3, 4]
[1,2].concat([3],[4,5],[6]); //[1, 2, 3, 4, 5, 6]
//添加一个元素到头部
[1].concat([2,3]);//[1, 2, 3]
//添加一个元素到尾部
[1,2].concat(3);//[1, 2, 3]

slice 从现有的数组返回选定的元素组成的数组 不改变原有数组

arrayObject.slice(start,end) start 和 end 定义了选取范围,正数从0开始,负数从-1开始,始终为左闭右开,也就是左边包含右边不包含

[1,2,3,4].slice(0,1);//[1]
[1,2,3,4].slice(1,3);//[2,3]
[1,2,3,4].slice(-1);//[4]
[1,2,3,4].slice(-2);//[3,4]
[1,2,3,4].slice(-2,-1);//[3]

splice 方法向/从数组中添加/删除项目,然后返回被删除的项目组成的新数组 会改变原有数组

arrayObject.splice(index,howmany,items,...)
index 起始位置,可以是负数
howmany 要删除的个数,0为不删除
items 要添加的元素

var arr1 = [1,2,3,4];
var arr2 = arr1.slice();
var arr3 = arr1.slice();
// 删除元素
var removed = arr1.splice(1,1);
console.log(removed);//[2]
console.log(arr1); //[1, 3, 4]
//删除了索引为1的元素2,并返回这个元素,原数组发生改变
// 替换元素
var replace = arr2.splice(2,1,5);
console.log(replace);//[3]
console.log(arr2);//[1, 2, 5, 4]
// 在索引为2的位置,删除了1个元素3,并在此插入新的元素5,返回了删除的元素,原数组发生变化
// 删除并插入元素
var insert = arr3.splice(3,0,5,6,7);
console.log(insert); //[]
console.log(arr3); //[1, 2, 3, 5, 6, 7, 4]
// 在索引为3的位置,删除0个元素,插入了5、6、7这3个元素到索引为3的前面

数组排序

sort / reverse
sort 用于对数组的元素进行排序
将对原数组操作,会改变原数组

arrayObject.sort(sortFn)
sortFn 为函数,用于提供排序比较规则,返回值是正值,则第一个参数比第二个大,负值,则第1个比第2个小,零,则两个数相等
如果sortFn为空,则按照字符编码的顺序进行排序

[1,51,4,12,2,3].sort() //[1, 12, 2, 3, 4, 51]
[1,51,4,12,2,3].sort(function(a,b){return a-b}) //[1, 2, 3, 4, 12, 51]
[1,51,4,12,2,3].sort(function(a,b){return b-a}) //[51, 12, 4, 3, 2, 1]
//或者
[1,51,4,12,2,3].sort(new Function('a','b','return a-b'))
[1,51,4,12,2,3].sort((a,b)=>a-b)

reverse 用于颠倒数组中元素的顺序 会改变原有的数组

[1,3,4,5].reverse() //[5, 4, 3, 1]
//反转字符串
'54321'.split('').reverse().join(''); //'12345'
//反转数字
Number(Number(12345).toString().split('').reverse().join('')) //54321

为数组增减元素

  • push 添加 元素至数组尾部,返回新的数组长度
  • unshift 添加 元素至数组开头,返回新的数组长度
  • pop 删除 尾部元素,返回删除的元素
  • shift 删除 头部元素,返回删除的元素

都是直接对原数组操作,会改变原有数组

var arr = [1,2,3,4];
var arr1 = arr.slice();
var arr2 = arr.slice();
var arr3 = arr.slice();
var arr4 = arr.slice();
console.log(arr1.push(5), arr1); //5 [1, 2, 3, 4, 5]
console.log(arr2.unshift(0), arr2); //5 [0, 1, 2, 3, 4]
console.log(arr3.pop(), arr3); //4 [1, 2, 3]
console.log(arr4.shift(), arr4); //1 [2, 3, 4]

数组转字符串
toString / join

[1,2,3,4].toString() //"1,2,3,4"
[1,2,3,4]+'' //"1,2,3,4"
[1,2,3,4].join('-');//"1-2-3-4"

ES5新增

  • Array.isArray()
  • [].indexOf() / [].lastIndexOf()
  • [].forEach / [].map()
  • [].every() / [].some()
  • [].filter()
  • [].reduce() / [].reduceRight()

数组类型判断

自定义一个方法来判断是否为数组

function isArray(obj){
  return Object.prototype.toString.call(obj) === '[object Array]';
}
isArray([]); //true

ES5新增 Array.isArray() 来判断是否为数组

Array.isArray([]);//true
Array.isArray({a:1});//false
// IE9以下兼容写法
if(typeof Array.isArray !== 'function'){
  Array.isArray = function(obj){
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
}

查找元素

indexOf(el, startIndex) / lastIndexOf(el, lastIndex)
没有查找到元素返回-1,查找到元素,返回查找到的第一个的索引值,lastIndexOf 为从后面查起

  • startIndex 表示从哪个索引开始找,默认为第1个索引
  • lastIndex 表示从倒数第几个索引开始找,默认为最后一个索引
[1,2,3,2,4].indexOf(2); //1
[1,2,3,2,4].indexOf(2,2); //3
[1,2,3,2,4].lastIndexOf(2); //3
[1,2,3,2,4].indexOf(5); //-1
[1,'1'].indexOf('1');//1
// 下面的查找返回了-1,=== 运算符的缺陷,后面ES6的includes方法会弥补这一缺陷
[1,NaN].indexOf(NaN);//-1
[1,{}].indexOf({});//-1
// IE9以下兼容写法
if(Array.prototype.indexOf !== 'function'){
  Array.prototype.indexOf = function(searchEl, startIndex){
    var index = -1;
    startIndex = startIndex * 1 || 0;
    for (var k = 0, len = this.length; k < len; k++) {
      if (k >= startIndex && this[k] === searchEl) {
          index = k;
          break;
      }
    }
    return index;
  }
}
if(Array.prototype.lastIndexOf !== 'function'){
  Array.prototype.lastIndexOf = function(searchEl, lastIndex){
    var index = -1, len = this.length;
    lastIndex = lastIndex * 1 || len;
    while (len--) {
      if (len <= lastIndex && this[len] === searchEl) {
           index = len;
           break;
       }
    }
    return index;
  }
}

数据遍历

[].forEach() / [].map()
[].forEach(function(value, index, arr){}, context)
循环遍历数组中的每一个元素,处理函数中的参数依次为:当前元素、当前元素索引、原数组
forEach的第二个参数,可以指定处理函数中this的指向

var arr = [1,2,3];
arr.forEach(function(v,i,a){
  console.log(v,i,a);
  v+=1;
})
console.log(arr); //[1,2,3]
// 1 0 [1, 2, 3]
// 2 1 [1, 2, 3]
// 3 2 [1, 2, 3]
 // 等同于
 for(var i=0; i<arr.length; i++){
   console.log(arr[i], i, arr);
 }
// IE9以下的兼容性写法
if(Array.prototype.forEach !== 'function'){
  Array.prototype.forEach = function(fn, context){
    for(var i=0, len=this.length; i<len; i++){
      if(typeof fn === 'function' && Object.prototype.hasOwnProperty.call(this, i)){
        fn.call(context, this[i], i, this);
      }
    }
  }
}

jQuery中的 $.each(function(index, values, arr){}) 回调中的参数第1个是索引,第2个是元素,$.map() 亦是如此

map(function(value, index, arr){}) 与forEach类似,返回一个新的数组,不改变原有数组

var arr = [1,2,3];
var res = arr.map(function(v){
  return v+1;
});
console.log(arr); //[2, 3, 4]
console.log(res); //[1, 2, 3]
// IE9以下的兼容性写法
if(Array.prototype.map !== 'function'){
  Array.prototype.map = function(fn, context){
    var res = [];
    if(typeof fn === 'function'){
      for(var i=0, len=this.length; i<len; i++){
        res.push(fn.call(context, this[i], i, this));
      }
    }
    return res;
  }
}

map的回调处理函数一定要有返回值,如果没用,则会返回undefined

检测是否包含某元素

[].every(function(value, index, arr){}, context) / [].some(function(value, index, arr){}, context)

  • 数组元素的逻辑判定,回调函数返回true/false
  • some是所判定的元素只要数组中有一个符合条件就返回true
  • ervery是数组中必须所有元素都符合条件就返回true,否则返回false
  • 在空数组上调用every返回true,some返回false
console.log([1,2,3,4].some(v=>v>3)) //true
console.log([1,2,3,4].every(v=>v>3)) //false
console.log([].every(v=>v>3)) //true
console.log([].some(v=>v>3)) //false
// IE9以下兼容写法
if(Array.prototype.some !== 'function'){
  Array.prototype.some = function(fn, context){
    var passed = false;
    if (typeof fn === "function") {
          for (var k = 0, length = this.length; k < length; k++) {
          if (passed === true) break;
          passed = !!fn.call(context, this[k], k, this);
      }
      }
    return passed;
  }
}
if (typeof Array.prototype.every != "function") {
  Array.prototype.every = function (fn, context) {
    var passed = true;
    if (typeof fn === "function") {
       for (var k = 0, length = this.length; k < length; k++) {
          if (passed === false) break;
          passed = !!fn.call(context, this[k], k, this);
      }
    }
    return passed;
  };
}

数组过滤

[].filter(fn, context)

  • 当遍历元素时,fn返回true,则返回这个元素,否则不返回,fn中返回值只要弱等于true或false即可,使用==比较
  • filter返回一个新的结果数组,不改变原有数组
[1,2,3,4].filter(v=>v>2); //[3, 4]
[1,2,0,null,''].filter(v=>v); //[1, 2]
// IE9以下兼容写法
if(Array.prototype.some !== 'function'){
  Array.prototype.some = function(fn, context){
    var arr = [];
    if (typeof fn === "function") {
       for (var k = 0, length = this.length; k < length; k++) {
          fn.call(context, this[k], k, this) && arr.push(this[k]);
       }
    }
    return arr;
  }
}

数组聚合

[].reduce(fn, initialValue) / [].reduceRight(fn, initialValue)

  • 将数组元素聚合(合并)为一个元素
  • fn 的参数依次为 (之前值、当前值、索引值、数组本身),
  • initialValue 表示最初的值,如果不存在,初始值为数组第1个元素

reduceRight 与 reduce 用法一致,区别是从最后一个元素开始迭代

ar res = [1,2,3,4].reduce(function(prev, curr, index, arr){
  console.log(prev, curr, index, arr);
  return prev+=curr;
})
console.log(res);//10
// 没有initialValue,则初始值为1
// 1 2 1 [1, 2, 3, 4]
// 3 3 2 [1, 2, 3, 4]
// 6 4 3 [1, 2, 3, 4]
[1,2,3,4].reduce(function(prev, curr, index, arr){
  console.log(prev, curr, index, arr);
  return prev+=curr;
}, 10)
// 如果initialValue有值,则初始值为initialValue的值
// 10 1 0 [1, 2, 3, 4]
// 11 2 1 [1, 2, 3, 4]
// 13 3 2 [1, 2, 3, 4]
// 16 4 3 [1, 2, 3, 4]
[1,2,3,4].reduceRight(function(prev, curr, index, arr){
  console.log(prev, curr, index, arr);
  return prev+=curr;
})
// 从最后一个元素开始迭代,初始值为4
// 4 3 2 [1, 2, 3, 4]
// 7 2 1 [1, 2, 3, 4]
// 9 1 0 [1, 2, 3, 4]
// 二维数组扁平化
[[1,2],[3,4]].reduce((prev,curr)=>prev.concat(curr)) //[1, 2, 3, 4]
// IE9以下兼容写法
if (typeof Array.prototype.reduce != "function") {
  Array.prototype.reduce = function (fn, initialValue ) {
     var prev = initialValue, k = 0, len = this.length;
     if (typeof initialValue === "undefined") {
        prev = this[0];
        k = 1;
     }
    if (typeof fn === "function") {
      for (k; k < len; k++) {
         this.hasOwnProperty(k) && (prev = callback(prev, this[k], k, this));
      }
    }
    return previous;
  };
}
if (typeof Array.prototype.reduceRight != "function") {
  Array.prototype.reduceRight = function (fn, initialValue ) {
    var len = this.length, k = len - 1, prev = initialValue;
    if (typeof initialValue === "undefined") {
        prev = this[len - 1];
        k--;
    }
    if (typeof fn === "function") {
       for (k; k > -1; k--) {          
          this.hasOwnProperty(k) && (prev = callback(prev, this[k], k, this));
       }
    }
    return previous;
  };
}

ES6新增

Array.from(arrLike) //类数组转数组
Array.of(…args) //将一组值转成数组
[].copyWithin(target, start, end) //复制数组成员到指定位置,会覆盖原有成员
[].find(fn) // 查找元素,返回元素本身
[].findIndex(fn) // 查找元素返回元素索引,没有则返回-1
[].includes() // 检测数组是否包含某元素,返回true/false
[].fill(value, start, end) //填充数组
[].keys() // 返回数组的key组成的数组
[].values() // 返回数组的值组成的数组
[].entries() // 返回数组索引和值组成的数组

数组转换

Array.from(arrLike) / Array.of(...args)

Array.from 可以将类数组(有length属性的Object/可遍历(iterable)的对象/Set对象/Map对象)转换为数组

let arrayLike = {'0':'a', '1':'b', '2':'c', length:3};
// 以前的写法
[].slice.call(arrayLike)//["a", "b", "c"]
// 使用Array.from
let arr1 = Array.from(arrayLike); //["a", "b", "c"]
let set = new Set([1,3,4,5]);
let arr2 = Array.from(set);//[1,3,4,5]
let map = new Map([[1,'a'], [2,'b'], [3,'c']]);
let arr3 = Array.from(map);//[[1,'a'],[2,'b'],[3,'c']]
let arr = [1,2,3,4];
let iter = arr[Symbol.iterator]();
iter.next();//{value: 1, done: false}
let arr4 = Array.from(iter); //[2,3,4]

Array.of 用于将一组值转换为数组

使用 Array 的构造函数初始化数组时,如果参数是1个,那么会创建这个参数长度的数组,数组的每一项为 undefined,如果参数是多个,那么会创建这多个参数组成的数组,所以参数的个数会导致结果的不一致,Array.of 正是弥补这一点的扩展

Array(2);//[,]
Array(2,3);//[2,3]
Array.of(2);//[2]
Array.of(2,3);//[2,3]

未完待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,924评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,902评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,716评论 0 239
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,783评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,166评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,510评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,784评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,476评论 0 196
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,196评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,459评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,978评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,321评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,964评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,046评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,803评论 0 193
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,530评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,420评论 2 265

推荐阅读更多精彩内容