jacascript 数组

前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

数组的增删

  • 第一个数组元素的索引值为 0,第二个索引值为 1,始终递增。
  • 数组可以在头部增加元素arr.unshift()
    • 也可以在尾部增加元素arr.push()
    • 增加元素的共同点是都是在原数组上修改,可顺序添加多个元素,并且返回数组的新长度。
  • 数组可以在头部删除元素arr.shift()
    • 也可以在尾部删除元素arr.pop()
    • 删除元素的共同点是都是在原数组上修改,一次只删一个元素,并且返回这个被删掉的元素。
  • 由于arr.unshift()有兼容性问题,我们可以用arr.splice(0,0,item1,...)代替,来在首位添加元素。

arr.push(newElement1,newElement2...)

  • 将新参数按顺序添加到原数组尾部。
  • 它是直接在原数组上修改。
  • 返回值是数组的新长度。
var arr = [123, 'apple'];

console.log(arr.push({
  name: 'lucy',
  age: 18
}, 'lily', 456)); //5
console.log(arr); //[123,'apple',{name:'lucy',age:18},'lily',456]

arr.pop()

  • 删除并返回数组的最后一个元素。
  • 它是直接在原数组上修改,所以数组长度-1。
  • 如果原数组本身已经没有元素,那么会返回undefined
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];

console.log(arr.pop()); //{name:'lucy',age:18}
console.log(arr); //[123,'apple']

console.log(arr.pop()); //apple
console.log(arr); //[123]

console.log(arr.pop()); //123
console.log(arr); //[]

console.log(arr.pop()); //undefined

arr.unshift(newElement1,newElement2...)

  • 将新参数按顺序添加到原数组头部。
  • 它是直接在原数组上修改。
  • 标准浏览器中返回值是数组的新长度,IE6/IE7 中返回值是undefined,所以这个方法会产生兼容性问题,一般不用。
  • 我们可以用arr.splice(0,0,item1,...)代替,来在首位添加元素;
var arr = [123, 'apple'];

console.log(arr.unshift({
  name: 'lucy',
  age: 18
}, 'lily', 456)); //5
console.log(arr); //[{name:'lucy',age:18},'lily',456,123,'apple']

arr.shift()

  • 删除并返回数组的第一个元素。
  • 它是直接在原数组上修改,所以数组长度-1。
  • 如果原数组本身已经没有元素,那么会返回undefine
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];

console.log(arr.shift()); //123
console.log(arr); //['apple',{name:'lucy',age:18}]

console.log(arr.shift()); //apple
console.log(arr); //[{name:'lucy',age:18}]

console.log(arr.shift()); //{name:'lucy',age:18}
console.log(arr); //[]

console.log(arr.shift()); //undefined

数组转换字符串

arr.join('分隔符')

  • 把数组元素放入一个新的字符串中(原数组并没有被改变),元素通过分隔符分隔。原数组不变。
  • 如果不写分隔符,则默认用逗号分隔。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];
//默认不分割,直接在最外层转换字符串包括了里面的逗号
console.log(arr.join()); //123,apple,[object Object]

//有引号,但没有分割内容,以逗号分隔,然后拼接字符串
console.log(arr.join('')); //123apple[object Object]
//以空格为分隔符
console.log(arr.join(' ')); //123 apple [object Object]
//注意原arr本身并没有被改变
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

arr.toString()

  • 把数组转换为字符串,并返回结果。
  • 元素之间用逗号分隔。
  • 原数组本身并没有被改变。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];
console.log(arr.toString()); //123 apple [object Object]
//注意原arr本身并没有被改变
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

其他类型转换成数组

Array.of(newElement1,newElement2,...)

  • Array.of用于将参数依次转化为新数组中的一项,然后返回这个新数组,而不管这个参数是数字还是其它。
Array.of(8.0, 5); // [8, 5]
Array(8.0, 5); // [8, 5]

//IE6-IE8兼容性写法
if (!Array.of){
  Array.of = function(){
    return Array.prototype.slice.call(arguments);
  };
}

Array.from(arrayLike,processingFn,[thisArg])

  • Array.from的设计初衷是快速便捷的基于其他对象创建新数组,准确来说就是从一个类似数组的可迭代对象创建一个新的数组实例。简单说就是,只要一个对象有迭代器,Array.from就能把它变成一个数组(当然,是返回新的数组,不改变原对象)。
  • Array.from拥有3个形参,第一个为类似数组的对象,必选。第二个为加工函数,新生成的数组会经过该函数的加工再返回。第三个为this作用域,表示加工函数执行时this的值。后两个参数都是可选的。我们来看看用法。
// String
Array.from('abc'); // ["a", "b", "c"]
// Set
Array.from(new Set(['abc', 'def'])); // ["abc", "def"]
// Map
Array.from(new Map([[1, 'abc'], [2, 'def']])); // [[1, 'abc'], [2, 'def']]
// 天生的类数组对象arguments
function fn(){
  return Array.from(arguments);
}
fn(1, 2, 3); // [1, 2, 3]

// 生成一个从0到指定数字的新数组
Array.from({length: 10}, (v, i) = i); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

数组的裁剪、拼接

arr.slice(start,end)

  • 返回的是一个新的数组(选定的元素),从引脚startend(不包含)。
  • 原数组并没有被改变。
  • start可以设置负值,负值就是从数组末尾开始,-1是最后一个元素,-2是倒数第二个元素。
  • end是可选值,如果没有设置end,就默认截取到数组末尾。
  • 数组的arr.slice()string.slice()很相似。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];

console.log(arr.slice(0)); //[123,'apple',{name:'lucy',age:18}]
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

console.log(arr.slice(1)); //['apple',{name:'lucy',age:18}]
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

console.log(arr.slice(0, 0)); //[]
console.log(arr.slice(0, 1)); //[123]
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

console.log(arr.slice(-2)); //['apple',{name:'lucy',age:18}]
console.log(arr.slice(-2, -1)); //['apple']

arr.splice(index,howmany,item1,item2...)

  • 原数组从引脚index处删除howmany个元素,并且用item1...代替这些被删除的元素。
  • 返回这些被删除的元素(用数组形式)。如果index为负值,则从数组末尾开始删除。
  • 如果howmany值是0,则不会删除元素,我们可以利用这一特性在数组中间部位插入元素。
  • 该方法是直接在原数组身上修改,这一点和arr.slice()不同。它们的相同点是都返回选定的元素。
  • 由于arr.unshift()有兼容性问题,我们可以用arr.splice(0,0,item1,...)代替,来在首位添加元素。
var test = [123, 'apple', {
  name: 'lucy',
  age: 18
}];
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];

console.log(test.splice(0)); //[123,'apple',{name:'lucy',age:18}]
console.log(test); //[]  被删完了

console.log(arr.splice(1, 0)); //[] 返回截取(删除)的元素
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

console.log(arr.splice(0, 0, 'lily')); //[] 返回截取(删除)的元素
console.log(arr); //['lily',123,'apple',{name:'lucy',age:18}]  没有删除元素,并且在首位还添加了一个元素

console.log(arr.splice(2, 2, 'poly')); //['apple',{name:'lucy',age:18}] 返回截取(删除)的元素
console.log(arr); //['lily',123,'poly']

console.log(arr.splice(-2)); //[123,'poly']  返回截取(删除)的元素
console.log(arr); //['lily']

arr.concat(arrayX,arrayX...)

  • 连接一个或多个数组,原数组不会改变,返回一个新数组。
  • 如果要进行concat()操作的参数是一个数组,那么添加的是该数组中的每一个元素。
  • 如果添加的数组没有声明,可直接连接元素,添加在数组末尾,相当于arr.push(),但返回的是一个新数组。
var test = ['good', 789];
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}];

//如果添加的数组没有声明,可直接连接元素,添加在数组末尾,相当于arr.push(); 但返回的是一个新数组;
console.log(arr.concat('abcdef', 'lily', 456)); //[123, "apple", {name:'lucy',age:18}, "abcdef", "lily", 456]
console.log(arr); //[123, "apple", {name:'lucy',age:18}]
//数组添加自身
console.log(arr.concat(arr)); //[123, "apple", {name:'lucy',age:18}, 123, "apple", {name:'lucy',age:18}]
console.log(arr); //[123, "apple", {name:'lucy',age:18}]

console.log(arr.concat(test)); //[123, "apple", {name:'lucy',age:18}, "good", 789]
console.log(arr); //[123,'apple',{name:'lucy',age:18}]

arr.fill(value, start, end)

  • 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。
  • 直接修改原数组并返回。
  • start:可选 起始索引,默认值为0
  • end:可选 终止索引,默认值为this.length
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
let arr3 = [1, 2, 3];
let arr4 = [1, 2, 3];
let arr5 = [1, 2, 3];
let arr6 = [1, 2, 3];

let newarr = arr1.fill(7);
console.log(arr1); //[7, 7, 7]
console.log(newarr); //[7, 7, 7]

arr2.fill(4);
console.log(arr2); // [4, 4, 4]

arr3.fill(4, 1);
console.log(arr3); // [1, 4, 4]

arr4.fill(4, 1, 2);
console.log(arr4); // [1, 4, 3]

arr5.fill(4, 1, 1);
console.log(arr5); // [1, 4, 3]

arr6.fill(4, 3, 3);
console.log(arr6); // [1, 2, 3]

数组排序

arr.reverse()

  • 颠倒数组中元素的顺序。
  • 直接在原数组身上修改。
  var arr = [123,'apple',{name:'lucy',age:18}];
  console.log(arr.reverse());//[{name:'lucy',age:18}, "apple", 123]

arr.sort( 函数 )

  • 对数组的顺序进行排序。
  • 直接在原数组身上修改。
  • 默认按照字符编码的顺序进行排序,如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。
  • 比较函数应该具有两个参数ab,其返回值如下:
    • a > b, 即a - b > 0,则返回一个大于0的值,数组将按照降序排列,即a b升序。
    • a < b,即a - b < 0,则返回一个小于0的值,数组将按照升序排列,即b a降序。
    • a = b,则返回0,顺序不变。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, 'banana'];
console.log(arr.sort()); //[123, 1456, 456, Object, "apple", "banana"]

var numSortCompare = function (a, b) {
  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else {
    return 0;
  }
  // 三元写法 return a > b ? (1 : a < b ? -1 : 0) : 0 
}

var sortTest1 = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, 'banana'];
console.log(sortTest1.sort(numSortCompare)); //[123, Object, "apple", 456, 1456, "banana"]

// 按编码顺序排序
var sortTest2 = [1, 1043, 78, 1043, -98, 652, 0, 205, 205];
console.log(sortTest2.sort()); //[-98, 0, 1, 1043, 1043, 205, 205, 652, 78]

// 按数值大小排序,小的在前
var sortTest3 = [1, 1043, 78, 1043, -98, 652, 0, 205, 205];
console.log(sortTest3.sort(numSortCompare)); //[-98, 0, 1, 78, 205, 205, 652, 1043, 1043]

// 按数值大小排序,大的在前
// 这里我们一般不改函数,而是先比较,然后再反向;
var sortTest4 = [1, 1043, 78, 1043, -98, 652, 0, 205, 205];
console.log(sortTest4.sort(numSortCompare).reverse()); //[1043, 1043, 652, 205, 205, 78, 1, 0, -98]

数组查找

arr.indexOf(find,start)

  • 来定位数组中某指定元素首次出现的位置(返回索引),如果没找到返回-1
  • start是从哪个位置开始找;如果没有就是默认从0开始。
  • arr.indexOf()只有在IE9+有效,在IE8中右兼容性问题。
  • arr.indexOf()string.indexOf()类似。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, 'banana'];

console.log(arr.indexOf(456)); //3
console.log(arr.indexOf('apple')); //1
console.log(arr.indexOf(456, 5)); //-1

console.log(arr.indexOf('sss')); //-1
//非0为true;0为false; 所以这里-1也为true;
if (arr.indexOf('sss')) {
  console.log('没找到sss');
}

//arr.indexOf()兼容处理如下
if (typeof Array.prototype.indexOf != "function") {
  Array.prototype.indexOf = function (searchElement, fromIndex) {
    var index = -1;
    fromIndex = fromIndex * 1 || 0;

    for (var k = 0, length = this.length; k < length; k++) {
      if (k = fromIndex && this[k] === searchElement) {
        index = k;
        break;
      }
    }
    return index;
  };
}

arr.lastIndexOf(find,start)

  • 来定位数组中某指定元素最后一次出现的位置(返回索引),如果没找到返回-1
  • start是从哪个位置开始找;
  • indexOf的逆向查找,即从数组最后一个往前查找。如果没有就是默认从length-1开始。
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, 'apple', 'banana'];

console.log(arr.lastIndexOf('apple')); //5

//arr.lastIndexOf()兼容处理如下
if (typeof Array.prototype.lastIndexOf != "function") {
  Array.prototype.lastIndexOf = function (searchElement, fromIndex) {
    var index = -1,
      length = this.length;
    fromIndex = fromIndex * 1 || length - 1;

    for (var k = length - 1; k  -1; k -= 1) {
      if (k <= fromIndex && this[k] === searchElement) {
        index = k;
        break;
      }
    }
    return index;
  };
}

arr.includes(searchElement, fromIndex)

  • includes()方法用来判断一个数组是否包含一个指定的值,如果是返回true,否则false
  • 对象数组不能使用includes方法来检测。
var test = {
  name: 'Jim',
  age: 22
}
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, test, 'banana'];

console.log(arr.includes('banana')); //true
console.log(arr.includes({
  name: 'lucy',
  age: 18
})); //false   对象数组不能使用`includes`方法来检测。
console.log(arr.includes(test)); //true 

arr.find((value, index, arr) => {},thisValue)

  • 返回符合条件的第一个元素的值,之后的值不会再调用执行函数。
  • 如果没有符合条件的元素返回undefined
var test = {
  name: 'Jim',
  age: 22
}
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, test, 'banana'];

console.log(arr.find(i => i == 'banana')); //banana
console.log(arr.find(i => i == test)); //{name: "Jim", age: 22}

console.log(arr.find(i => i.age == 18)); //{name: "lucy", age: 18}

console.log(arr.find(i => i == {
  name: 'lucy',
  age: 18
})); //undefined

arr.findIndex((value, index, arr) => {}, thisValue)

  • 返回符合条件的第一个元素位置,之后的值不会再调用执行函数。
  • 如果没有符合条件的元素返回-1
var test = {
  name: 'Jim',
  age: 22
}
var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, test, 'banana'];

console.log(arr.findIndex(i => i == 'banana')); //6
console.log(arr.findIndex(i => i == test)); //5

console.log(arr.findIndex(i => i.age == 18)); //2

console.log(arr.findIndex(i => i == {
  name: 'lucy',
  age: 18
})); //-1

数组遍历

arr.forEach((value,index,arr) => {},[thisObject])

  • forEach方法中的回调函数支持3个参数(遍历的数组元素,该索引,数组本身)。
  • [thisObject]为可选参数,可改变回调函数的this指向。
  • forEach不会遍历空的元素。
  • 理论上这个方法是没有返回值的,仅仅是遍历数组中的每一项,不对原来数组进行修改。但是可以自己通过数组的索引来修改原来的数组。
var test1 = [123, 'apple', , {
  name: 'lucy',
  age: 18
}];

test1.forEach(console.log);
//结果如下,注意没有索引为2的元素
//123 0 [123, "apple", Object]
//apple 1 [123, "apple", Object]
//Object {name: "lucy", age: 18} 3 [123, "apple", Object]

var sum = 0;
test1.forEach((value, index, arr) => {
  sum += value;
})
console.log(sum); //123apple[object Object]

function titleCase(str) {
  var newarr = str.toLowerCase().split(" ");
  newarr.forEach((i, k) => {
    newarr[k] = i.replace(i.charAt(0), i.charAt(0).toUpperCase());
  })
  return newarr.join(" ");
}
console.log(titleCase("I'm a javascript coder")) //I'm A Javascript Coder

//IE6-IE8兼容性写法
if (typeof Array.prototype.forEach != "function") {
  Array.prototype.forEach = function (fn, context) {
    for (var k = 0, length = this.length; k < length; k++) {
      if (typeof fn === "function" && Object.prototype.hasOwnProperty.call(this, k)) {
        fn.call(context, this[k], k, this);
      }
    }
  };
}

arr.map((value,index,arr) => {},[thisObject])

  • 在实际使用中,我们可以用arr.map()得到数组中特定的属性值。
  • map的回调函数中支持return返回值。相当于把数组中的这一项变为return的值(并不影响原数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了)。
var arr = [{
  name: 'lily',
  age: '16'
}, {
  name: 'meno',
  age: '18'
}, {
  name: 'jim',
  age: '17'
}];
var ageData = arr.map((value) => {
  return value.age;
})
console.log(ageData); //['16','18','17']

//IE6-IE8兼容性写法
if (typeof Array.prototype.map != "function") {
  Array.prototype.map = function (fn, context) {
    var arr = [];
    if (typeof fn === "function") {
      for (var k = 0, length = this.length; k < length; k++) {
        arr.push(fn.call(context, this[k], k, this));
      }
    }
    return arr;
  };
}

arr.filter((value,index,arr) => {},[thisObject])

  • 遍历所有元素,返回一个新数组,新数组包含符合条件的所有元素。
var test1 = [123, 'apple', , {
  name: 'lucy',
  age: 18
}];

var ageData = test1.filter(value => value.age > 10)
console.log(ageData); //[{name: "lucy", age: 18}]

//IE6-IE8兼容性写法
if (typeof Array.prototype.filter != "function") {
  Array.prototype.filter = 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;
  };
}

arr.some((value,index,arr) => {},[thisObject])

  • 检测数组中的元素是否存在满足指定条件的元素。只要有1个返回true,后面就不执行了。
  • 返回Boolean
var test1 = [123, 'apple', , {
  name: 'lucy',
  age: 18
}];

//验证所有元素中是否存在age属性,存在返回true,只要验证到存在1个,后面就不继续验证了
var ageData = test1.some(value => value.age)
console.log(ageData); //true

//IE6-IE8兼容性写法
if (typeof 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;
  };
}

arr.every((value,index,arr) => {},[thisObject])

  • 验证所有元素,都满足条件,才返回true
  • 如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测。
var test1 = [123, 'apple', , {
  name: 'lucy',
  age: 18
}];

//验证所有元素中是否都存在age属性,只要有1个不存在,就返回false,
var ageData = test1.every(function (value) {
  return value.age; 
})
console.log(ageData); //false

var ageData2 = test1.every(value => value.age)  
console.log(ageData2); //false

var test2 = [5, 6, 7, 8, 9];
var bigger4 = test2.every((value) => {
  return value > 4;
})
console.log(bigger4); //true

//IE6-IE8兼容性写法
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;
  };
}

arr.reduce((previous,current,index,array) => {},initialValue)

  • 接收一个方法作为累加器,数组中的每个值(从左至右) 开始合并,最终为一个值。
  • callback有4个参数(previous,current,index,array)previous为初始值, 或者计算结束后的返回值,current为当前元素,index索引,array数组本身。
  • iniaialValue为可选参数,表示初始值,如果设置了这个值,就是最初的previous值,current为之后的元素;如果没有设置,则previous值为数组第一个元素,current为第二个元素。
var test1 = [123, 'apple', , {
  name: 'lucy',
  age: 18
}];

var testData1 = test1.reduce((presious, current) => {
  return presious + current;
})
console.log(testData1); //123apple[object Object]
console.log(typeof testData1); //string

//二维数组扁平化
var test2 = [
  [2, 3, 4],
  [5, 6, 7, 8, 9],
  ['apple'],
  [345, 'banana']
];
var testData2 = test2.reduce((previous, current) => {
  return previous.concat(current);
})
console.log(testData2); //[2, 3, 4, 5, 6, 7, 8, 9, "apple", 345, "banana"]

//IE6-IE8兼容性写法
if (typeof Array.prototype.reduce != "function") {
  Array.prototype.reduce = function (callback, initialValue) {
    var previous = initialValue,
      k = 0,
      length = this.length;
    if (typeof initialValue === "undefined") {
      previous = this[0];
      k = 1;
    }

    if (typeof callback === "function") {
      for (k; k < length; k++) {
        this.hasOwnProperty(k) && (previous = callback(previous, this[k], k, this));
      }
    }
    return previous;
  };
}

for...in 和 for...of

  • for...in的方式遍历的是数组中的索引,前面也提到过数组是一种特殊的对象,在默认的情况下是以0...n的数字作为索引,但是也可以用其他字符作为索引,所以当数组中存在其他索引的时候可以用for...in获取。
  • 当我们手动给Array对象添加了额外的属性后,for … in循环将带来意想不到的意外效果。
  • for ... of直接遍历数组中的值。
var arr = ['a','b','c'];
arr.k = "hello";

for(let i in arr){
  console.log(i+":"+arr[i]); //遍历的是属性值
}
/*
    0:a
    1:b
    2:c
    k:hello
 */
console.log(arr); // [ 'a', 'b', 'c', k: 'hello' ]

var arr2 = ['a','b','c'];
arr2.k = "hello";

for(let val of arr2){
    console.log(val);
}
/*
    a
    b
    c
*/

判断变量是否为数组

Array.isArray(testData)

var arr = [123, 'apple', {
  name: 'lucy',
  age: 18
}, 456, 1456, 'banana'];
console.log(Array.isArray(arr)); //true

//isArray在IE9+有效,考虑其兼容性,比较好的方法如下:
function isArrayFn(value) {
  if (!Array.isArray){
    Array.isArray = function(arg){
      return Object.prototype.toString.call(arg) === '[object Array]';
    };
  }
}
console.log(isArrayFn(arr)); //true
原文地址:https://www.cnblogs.com/sspeng/p/11445107.html