最详细的JavaScript高级教程(九)Array

Array类型是js中常用的引用类型。js中的Array最大的特点就是:数组可以容纳多种类型的元素,数组在定义的时候不用指明元素类型,一个数组中可以混杂多种数据类型。

创建数组

// 使用Array对象初始化
// 需要预先知道元素数量
var colors = new Array(10);
// 传入数字,则使用数字个数初始化数组
// 传入其他数据类型,则创建只有一个元素的数组
var colors = new Array('red');
// 使用多个元素初始化Array
var colors = new Array('red', 'blue', 'green');
// 省略new
var colors = Array(34);


// 使用字面量
var colors = ['red'];
// 创建空数组
var colors = [];
// 使用下面的写法在不同的浏览器中运行结果不同,不要使用
var colors = ['red'];
var colors = [, ,];

使用数组

数组可以自动扩充,当设置了数组之外的索引的值的时候,数组被自动扩充到需要的大小

var colors = new Array('red', 'blue', 'green');
console.log(colors.length); // 3
console.log(colors[5]); // 输出undefined
console.log(colors.length); // 3
colors[5] = '6';
console.log(colors.length); // 6

数组的length不是只读的,所以可以用于删除项或者新增项,新增的项都是undefined,数组的这个特性还有个很巧妙的用法就是用来添加新的项

// 裁切数组
var colors = new Array('red', 'blue', 'green');
colors.length = 2;
console.log(colors[2]); // undefined
// 在数组后追加一项
colors[colors.length] = 'new';
colors[colors.length] = 'new2'; // 再新增一项

检测对象是不是数组

当我们检测一个对象是不是数组的时候很容易想到使用 instanceof 来判断。我们复习一下 instanceof 是判断一个对象的原型的,我们通过判断对象是不是继承自Array就可以判断出来。

但是,这只是理论上可行,由于网页的运行环境复杂,很容易就包含多个框架,而多个框架就有可能有多个Array的构造函数,如果两个框架之间传递参数,就有可能判断有误,认为这个对象并不是继承自自己框架内的Array,导致判断失误。

正确的做法是使用ES5提供的Array.isArray方法

var colors = new Array('red', 'blue', 'green');
console.log(Array.isArray(colors)); // true
console.log(Array.isArray('123'));  // false

数组的输出

数组默认tostring是以逗号分隔输出的。

var colors = new Array('red', 'blue', 'green', null, undefined);
console.log(colors); //'red', 'blue', 'green', null, undefined 

当我们不想用逗号分隔,想用别的标识符分隔的时候,使用join函数

var colors = new Array('red', 'blue', 'green', null, undefined);
console.log(colors.join('|')); //red|blue|green||

注意当数组中有null和undefined的时候,不同环境的处理不同,node中会打印出null和undefined,在浏览器中都显示空字符串,而使用join,null和undefined都会转化为空字符串显示。

栈和队列

在js中,想使用栈和队列不需要再定义新的数据结构,使用数组即可,使用push入栈,使用pop弹出栈,使用shift出队列,有了这三个方法,我们就可以模拟入栈出栈,入队列出队列了

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.push('p');  // 入栈
console.log(colors.pop());  // 出栈,输出p

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.push('p');
console.log(colors.shift()); //red,从队列头弹出一个元素

但是,如果我们想实现一个相反的队列怎么办,从队列头进队列,从尾部消费。这时候我们需要用unshift像队列头添加元素,使用pop消费即可。

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.unshift('1');  // 在数组的头部添加一个元素
console.log(colors.pop()); //从尾部弹出undefined

入站,入队列这种给数组添加值的方法有返回值,其返回值是数组变更之后数组的长度。

排序

使用reverse方法反转数组顺序

var values = [0, 1, 15, 5, 10];
console.log(values.reverse()); // 10, 5, 15, 1, 0

使用sort可以更精确的排序,不添加参数它默认从小到大按照字符串顺序排序,这种方法会把 10 排到 5前面,不太好用,我们一般使用的时候给它传递一个函数进去来告诉它应该如何排序

var values = [0, 1, 15, 5, 10];
// 从大到小排列
function compare(value1, value2) {
  if (value1 < value2) {
    return 1;
  } else if (value1 > value2) {
    return -1;
  } else {
    return 0;
  }
}
// compare函数可以改写为
function compare2(value1, value2) {
  return value2 - value1;
}
// 注意sort方法会返回排序之后的数组
console.log(values.sort(compare)); //15, 10, 5, 1, 0

拼接多个数组

使用concat方法拼接数组,这个方法十分的灵活,可以传递一个对象,也可以传递一个数组,注意不是在原数组上进行拼接,而是返回一个新的数组

var a = [1];
var b = a.concat(2, [3, 4]);
console.log(b); //1, 2, 3, 4

切片

使用slice方法对于数组进行切片,注意切片这个函数的行为,主要有下面几点

  • 与concat方法一样,这个方法不修改原数组,返回一个新的数组
  • 传入一个参数,则指定了切片的起始位置,是从当前位置,一直切到结束
  • 传入两个参数,第二个参数指示结束位置,结束位置的元素不会被切出来
  • 当起始座标大于结束座标,返回空数组
  • 当参数位负数,使用length加上这个负数就是真正需要的值
var a = [1, 2, 3, 4];
console.log(a.slice(1, 3)); //2, 3 不包括位置为3的元素
console.log(a.slice(-1)); //4  length是4,4-1=3则从第三个元素截取到最后
console.log(a.slice(2, 1)); //空数组

删除,插入和替换

使用splice来完成这一系列复杂的操作,需要特别注意的是,splice方法会修改原数组,他的返回值是:如果有删除的项则返回删除的项

  • 删除,指定两个参数,第一个是起始位置,第二个是要删除的个数
  • 插入,指定3+个参数,第一个是起始位置,第二个删除个数填0,不删除,后面的参数填要插入的值,可以插入多个
  • 替换,指定3+个参数,第二个删除的值填写要被替换的值,可以删除一个添加多个,以达到替换的效果
var a = [1, 2, 3, 4];
// 删除第二个值
console.log(a.splice(1, 1)); // [2] 删除的项目,放到数组中返回
console.log(a); //1, 3, 4
var a = [1, 2, 3, 4];
// 插入
console.log(a.splice(1, 0, 9)); // 删除的项目,空数组
console.log(a); //1, 2, 9, 3, 4
var a = [1, 2, 3, 4];
// 替换
console.log(a.splice(1, 1, 9)); // 删除的项目,[2]
console.log(a); //1, 9, 3, 4

位置查找方法

再js中查找一个元素的位置的方法有两个

  • indexOf 从前往后查找
  • lastIndexOf 从后往前查找

他们的参数:第一个是要查找的元素,与数组中元素进行全等比较,第二个是可选参数,可以指定开始查找的位置

var a = [1, 2, 3, 4, 1];
alert(a.lastIndexOf(1, 3)); // 输出0, 从下标为3的元素向前查找1

迭代方法

很多时候我们需要将数组中的元素一一进行某些运算,这时候我们就要用到迭代方法。下面介绍所有的迭代方法,需要注意:

  • 迭代方法的参数都是一个方法,这个方法指示了要对数组中的元素做哪些操作
  • 所有的迭代方法都不会修改原数组中的值
  • 传入的方法有三个参数 第一个是该元素的字面值 第二个是该元素在数组中的位置 第三个是这个数组本身
    介绍迭代方法:
  • every 对数组中每一项都运行,如果每一项都返回true则结果为true。实际意义是判断所有的项都满足某个条件。
  • some 对数组中每一项都运行,如果其中一个返回true则运行结果为true。这个方法的实际意义是检测有没有一个元素满足某个条件
  • forEach 对数组中每一项都运行某个函数,没有返回值
  • map 对数组中每一项都运行某个函数,返回执行结果组成的数组
  • filter 对数组中每一项都运行某个函数,返回值为true的元素组成返回值返回
var a = [1, 2, 3, 4, 1];
var result = a.every(function(item, index, array){
    return item > 2; // 判断是不是所有的元素都大于2
});
alert(result);  // false
var a = [1, 2, 3, 4, 1];
var result = a.some(function(item, index, array){
    return item > 2; // 判断有没有元素大于2
});
alert(result);  // true
var a = [1, 2, 3, 4, 1];
var result = a.filter(function(item, index, array){
    return item > 2; // 过滤出大于2的元素
});
alert(result);  // 3, 4
var a = [1, 2, 3, 4, 1];
var result = a.map(function(item, index, array){
    return item * 2; // 所有的元素乘2返回数据
});
alert(result);  // 2, 4, 6, 8, 2
// 获取所有元素之和
// 只用数组的值,不用返回每次运行的值
var a = [1, 2, 3, 4, 1];
var sum = 0;
var result = a.forEach(function(item, index, array){
    sum += item;
});
alert(sum);  // 11

归并函数

js中的归并函数有reduce和reduceRight两个,区别显而易见,reduce是从左往右归并,后者是从右向左归并。

所谓归并函数,就是给出一个函数,数组中的值带入进行运算,运算的结果带入下一次运算继续运算。常用的地方是:

  • 数组求和
  • 数组求最大值
  • 数组去重
// 获取所有元素之和
var a = [1, 2, 3, 4, 1];
var result = a.reduce((para1, para2, index, array)=>{
    return para1 + para2;
});
alert(result); // 11
// 获取所有元素最大值
var a = [1, 2, 3, 4, 1];
var result = a.reduce((para1, para2, index, array)=>{
    return Math.max(para1, para2);
});
alert(result); //4
// 数组去重
var a = [1, 2, 3, 4, 1];
var result = a.reduce((prev, cur)=>{
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
}, []);
alert(result); //4

注意在去重的例子中,我们给reduce传入了第二个参数,这个参数指示了reduce运行的时候prev的初始值是什么,这样极大的扩展了reduce的用处。

注意

  • 数组最大可以包含 4294967295 个值,这个值非常大以至于我们一般不会考虑数组不够用的情况

ES6 - 解构赋值

在解构赋值出现之前,我们想把一个数组中的值分别赋值给几个变量,以前只能一个一个赋值,现在可以使用解构赋值。

解构赋值就是模式匹配,把相同位置的值赋值给相同位置的变量。

数组解构赋值的语法是:赋值等号的左边要使用数组包起来,右边要传一个可以迭代的对象。

在我们使用解构赋值的时候只需要下面几个原则:

  • 如果需要赋值的变量比提供的值多,没提供的值都是undefined
    let [a, b, c] = [1, 2];
    alert(a); //1
    alert(b); //2
    alert(c); //undefined
    
  • 如果需要赋值的变量比提供的值少,不会有影响
    let [a, b] = [1, 2, 3];
    alert(a); //1
    alert(b); //2
    
  • 数组里面可以嵌套数组,位置对应上就可以赋值
    let [a, [b, c]] = [1, [2, 3]];
    alert(a); //1
    alert(b); //2
    alert(c); //3
    
  • 如果对象本身就是数组,需要使用…来赋值
    let [a, ...b] = [1, 2, 3]; //想给b赋值为[2, 3]
    alert(a); //1
    alert(b); //[2, 3]
    
  • 等号的右边不一定是需要数组,只要是可以遍历的就可以
    let [first, second, third, fourth, fifth, sixth] = fibs();
    alert(first); //0
    alert(second); // 1
    alert(third); // 1
    alert(fourth); // 2
    alert(fifth); // 3
    alert(sixth); // 5
    
  • 等号右边如果不是可以遍历的就会报错
    let [a] = false; //报错 false is not iterable
    
  • 可以设置默认值以防止解构赋值失败,需要注意,只有变量等于undeifined的时候,才会触发默认值,null不会触发默认值
    // 设置默认值
    let [a, b = '1'] = ['w'];
    alert(a); //w
    alert(b); //1
    
    // null不会触发默认值
    let [a = 'w', b = '1'] = [undefined, null];
    alert(a); //w
    alert(b); //null
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章