JavaScript -- Array进阶详解

本文详细介绍了JavaScript中数组的创建、长度特性、检测方法、迭代器与迭代方法、复制填充方法以及栈和队列操作。通过示例解析了如Array.from(), .length, instanceof与Array.isArray(), 迭代器keys(), values(), entries(), every(), some(), filter(), forEach(), map(), copyWithin(), fill(), push(), pop(), unshift(), shift()等方法的用法,帮助开发者更好地掌握JS数组操作。" 107374452,9854070,Java全局异常处理机制详解,"['Java', '异常处理', 'Controller层']
摘要由CSDN通过智能技术生成

如没有特别说明,测试宿主环境为Node.js


前言

除了Object之外,Array应该ECMAScript中最常用的类型了,但和其他语言不一样,ECMAScript中的数组长度是可变的,而且由于ECMAScript的弱类型,这也使得数组Array中存取的类型可以是混杂的,例如数组的第一个元素可能是number类型,第二个可能是string类型,第三个可能又是Object,但通常我们不会这么做,更多地是使用统一的规范


一、逗号创建数组

我们来看两种有意思几种的逗号数组创建方式:

  1. 第一种

    var arr = [,,,]; 		   //创建包含三个空位的数组
    console.log(arr.length);   // => 3
    console.log(arr);		   // => [ <3 empty items> ]
    
  2. 第二种

    var arr = [2,,,6]; 		   //创建包含四个空位的数组
    console.log(arr.length);   // => 4
    console.log(arr);		   // => [ 2, <2 empty items>, 6 ]
    
  3. 第三种

    var arr = [2,,,]; 		   //创建包含三个空位的数组
    console.log(arr.length);   // => 3
    console.log(arr);		   // => [ 2, <2 empty items> ]
    
  4. 第四种

    var arr = [,,1,]; 		   //创建包含四个空位的数组
    console.log(arr.length);   // => 3
    console.log(arr);		   // => [ <2 empty items>, 1 ]
    
  5. 第五种

    var arr = [,,,3]; 		   //创建包含四个空位的数组
    console.log(arr.length);   // => 4
    console.log(arr);		   // => [ <3 empty items>, 3 ]
    

不知道你所预期的结果和实际输出的有没有区别,得到这样结果的原因是从ES5规范开始就允许在列表(数组值,属性列表)末尾多加一个逗号(在实际处理中会被忽略不计)

那如何简便判断数组的length呢?

如果你读懂了上文的解释,你或许猜到了,如果数组最后一个是, 控制台输出会忽略这个, 然后正常的思维计算数组长度,现在利用这个规律返回看看上面的五个示例,得到的结果是不是这样的呢?

数组创建的静态方法:
关于数组创建,这里我引入Array.from()Array.of()两个方法

  1. Array.from()
    //字符串会被拆分为单字符数组
    console.log(Array.from("hello"));   	// => ["h","e","l","l","o"];
    
    //对现有数组进行复制
    const arr1 = [1,2,3,4,5];
    const console.log(Array.from(arr1));    // => [1,2,3,4,5]
    console.log(arr1 === arr2);  			// => flase
    
    //还可接受第二个可选的映射函数参数,这个函数可以直接增强新数组的值,类似于调用函数map()
    const arr3 = [2,3,4,5];
    console.log(Array.from(arr3,x => x**2)); // =>[4,9,14,25]  注:** 相当于执行了Math.pow()函数
    
  2. Array.of()
    这个函数主要用在把一组参数转换为数组
    //以前我们通常会用如下函数返回一系列参数组成的数组
    function fn() {
        console.log(Array.prototype.slice.call(arguments));
    }
    fn(1, 2, 3, 4); // => [1,2,3,4]
    //但现在我们有了更简便的方法
    console.log(Array.of(1,2,3,4)); // => [1,2,3,4]
    

二、容易忽略的.length

JavaScript的数组长度length具有一些其他语言没有的特性

  1. 数组长度可变,可以更改length的值来修改数组长度
    let arr = ["a","b","c","d"];
    arr.length = 5;
    console.log(arr); // =>  ["a","b","c","d",undefined,underfined]; 注:未定义的单元用undefined填充
    arr.lengeh = 2;
    console.log(arr); // =>  ["a","b"]; 注:缩小数组长度会覆盖以前的以定义的单元
    
  2. 插入问题,设置某位置的值,有可能会改变数组长度,哪怕设置为undefined
    let arr = [2,4,6,8];
    console.log(arr); // => [ 2, 4, 6, 8 ]
    console.log(arr.length); // => 4
    
    arr[80] = 100;   
    console.log(arr); 	// => [ 2, 4, 6, 8, <76 empty items>, 100 ]
    console.log(arr.length); // => 81
    
    arr[99] = undefined;
    console.log(arr); 	// => [ 2, 4, 6, 8, <76 empty items>, 100, <18 empty items>, undefined ]
    console.log(arr.length); // => 100
    

三、检测数组的两种方法

说到检测数组,不管是在Java中还是JavaScript中,我们都不由想到instanceof操作符
这是正确的,你可以使用如下方法检测数组

const arr = [12,2,3,4];
console.log(arr instanceof Array);  // => true

我希望你也能知道还有一种少见但重要的检测方法,试想我们有两个框架在同一个网页中,涉及两个不同的全局执行上下文,就可能有两个不同版本的Array构造函数,如果把一个用第一个框架的声明的数组传入另一个框架,在用instanceof Array检测是否是数组,显然此时会返回false

因为 instanceof Array操作代表的并不是像我们理解的那样判断一个对象是不是数组,而是告诉我们该对象是否是当前全局作用域下的Array的实例

为了解决这个问题,ECMAScript提供了Array.isArray()方法,这个方法的目的就是确定一个值是否为数组,如下:

let arr = ['a','b','c','d'];
if (Array.isArray(arr)) {
	console.log('yes');	
}

四、迭代器方法(返回迭代器)

我们知道,对象Object有三个静态方法Object.keys()、Object.values()、Object.entries()

同样的,ECMAScript也在Array的对象原型上为我们添加了类似方法来实现数组的迭代

  1. Array.prototype.keys()
    这个方法返回数组 索引 的迭代器
    let arr = [3,5,7,9,11];
    console.log(Array.from(arr.keys())); // => [ 0, 1, 2, 3, 4 ]
    
  2. Array.prototype.values()
    这个方法返回数组 值 的迭代器
    let arr = [3,5,7,9,11];
    console.log(Array.from(arr.values()));  // => [ 3, 5, 7, 9, 11 ]
    
  3. Array.prototype.entries()
    这个方法返回数组 索引/值 对的迭代器
    let arr = [3,5,7,9,11];
    console.log(Array.from(arr.entries()));  // => [ [ 0, 3 ], [ 1, 5 ], [ 2, 7 ], [ 3, 9 ], [ 4, 11 ] ]
    

对,如你所想,Array.from()方法还可以接收迭代器,转为数组


五、迭代方法(返回boolean值或者Array对象)

你可能意识到了,上面的三种迭代器方法方法只能帮我们输出数组的内容,并不能做一些判断和操作,那么接下来的五个迭代方法将会对你操作数组提供更便捷的方式,传入的第一个参数为 断言函数,在某些方法中通常简写为匿名函数,如下就是采用匿名函数的形式,断言函数的三个参数分别为 值 、索引、该数组本身

  1. every():

对数组的每一项都运行传入的参数,如果对每一项函数都返回true,则这个方法返回true
像every翻译过来一样(全部),我们可以用这个方法来判断某个数组的所有值是否都满足某个条件,例如

let arr = [24,56,87,33,45];
console.log(arr.every((item, index, array) => item > 10));  //=> true  注:5个值都大于10,返回true
  1. some():

对数组的每一项都运行传入的参数, 如果有一项函数返回true,则这个方法返回true
像some翻译过来一样(某些),我们可以用这个方法来判断某个数组的某个值都满足某个条件

let arr = [24,56,87,33,45];
console.log(arr.some((item, index, array) => item > 80));  //=> true  注:87大于80,返回true
  1. filter():

对数组的每一项都运行传入的参数,函数返回true的项将会组成数组后返回
像filter翻译过来一样(过滤器),我们只挑选符合我们需求的值组成数组并返回

let arr = [24,56,87,33,45];
console.log(arr.filter((item, index, array) => item > 35));  //=> [56, 87, 45]  注:返回大于35的值组成的数组
  1. forEach():

对数组的每一项都运行传入的参数,类似于for循环,只是forEach会将每一项函数返回值组成数组返回

let arr = [24, 56, 87, 33, 45];
console.log(arr.filter((item, index, array) => arr[index])); //=>[ 24, 56, 87, 33, 45 ]

//等价于
let arr_2 = [];
for (let i = 0; i < arr.length; i++) {
    arr_2.push(arr[i]));  
}
console.log(arr_2);   //=>[ 24, 56, 87, 33, 45 ]
  1. map():

对数组的每一项都运行传入的参数,将每一项函数return返回的值组成数组后返回
可用此方法对数组的值进行操作改变后返回

let arr = [24, 56, 87, 33, 45];
console.log(arr.map(item, index, array) => item * 2);  //=>[ 48, 112, 174, 66, 90 ]

尽管有了如上的迭代器方法,可以很容易对数组进行我们想要的的操作,但我们还是感到对数组某些方面没有足够边便捷的操作,例如如何快速在头部和尾部添加值或者删减值(你可能注意到上文用了一次push函数),又或者如何对数组进行快速整齐地赋值,接下来两节着重围绕此进行说明


六、复制和填充方法

ES6新增了两个批量复制和填充数组的方法:

  1. Array.prototype.fill(value[, start[, end]])
    //一个参数时,默认value填充数组所有元素
    let arr = [1,2,3,4,5,6];
    arr.fill(5);
    console.log(arr); // =>[5,5,5,5,5,5]; 注:全被覆盖-
    
    //两个参数时,使用value填充大于等于start的元素
    let arr = [48653];
    arr.fill(2,5);
    console.log(arr); // =>[4,2,2,2,3]; 注:8,6,5都大于等于5,被覆盖
    
    //三个参数时,使用value填充大于等于start,小于等于end的元素
    let arr = [48653];
    arr.fill(2,5,6);
    console.log(arr); // =>[4,8,2,2,3]; 注:6,5都大于等于5,小于等于6,被覆盖
    
  2. Array.prototype.copyWithin(target[, start[, end]])
    //一个参数时,复制索引0的开始的内容,插值到索引start开始的地方
    let arr = [1,2,3,4,5,6];
    arr.copyWithin(2);
    console.log(arr); // =>[ 1, 2, 1, 2, 3, 4 ]; //注:复制索引0的开始的内容,插值到索引为2开始的地方
    
    //两个参数时,复制索引start的开始的内容,插值到索引target开始的内容
    let arr = [1, 2, 3, 4, 5, 6];
    arr.copyWithin(2, 3);
    console.log(arr); // =>[ 1, 2, 4, 5, 6, 6 ];  // 注:复制4,5,6,插值到下标为2开始的位置
    
    //三个参数时,复制索大于等于start,小于end的内容,插值到索引target开始的地方
    let arr = [1, 2, 3, 4, 5, 6];
    arr.copyWithin(2, 3, 5);
    console.log(arr); // =>[ 1, 2, 4, 5, 5, 6 ];  注:复制4,5,插入到索引值为2的地方
    

copyWithin()和fill()的参数满足以下条件

  • 负值索引从数组末尾开始计算
  • 静默忽略超出数组边界,0长度及方向反向的索引范围
  • 索引值有部分可用,则用该可用的部分

七、栈与队列方法

  1. Array.protype.push()
    //从数组尾部添加元素,返回新数组长度
    let arr = [1,2,3,4];
    console.log(arr.push(5,6)); // => 6 
    console.log(arr);	// => [1,2,3,4,5,6];
    
  2. Array.protype.pop()
    //从数组尾部删除一个元素,返回该删除的元素
    let arr = ["a","b","c","d"];
    console.log(arr.pop()); // => "d"
    console.log(arr);	// => ["a","b","c"];
    
  3. Array.protype.unshift()
    //从数组头部添加元素,返回新数组长度
    let arr = [1,2,3,4];
    console.log(arr.unshift(7,8,9)); // => 7
    console.log(arr);	// => [7,8,9,1,2,3];
    
  4. Array.protype.shift()
    	//从数组头部删除一个元素,返回该删除的元素
    let arr = [1,2,3,4];
    console.log(arr.shift()); // => 1 
    console.log(arr);	// => [2,3,4];
    

到现在应该算了解了操作数组的大部分方法,我们已经能对数组内部元素做许多操作了,接下来更深入了解数组本身的一些基本操作,如数组翻转,排序和数组之间的连接


八、翻转与排序

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值