2. 数组
2.1 数组创建
-
通过构造函数: new Array()
-
数组字面量。[]
-
Array.of() 。es6
-
Array.from(iterator, mapFn, thisArg) 从一个类似数组或可迭代对象中创建一个新的数组实例。es6
//1. new 通过构造函数
{
let arr1 = new Array(3); //length为3的空数组[]
let arr2 = new Array(1,2); //[1,2]
let arr3 = new Array('grace'); //['grace]
}
//通过构造函数,创建数组,可省略关键字new
{
let arr = Array(3,4);//[3,4]
arr instanceof Array; //true
}
//2. [] 通过数组字面量创建
{
let arr1 = [1, 2, 3];
let arr2 = [,,]; //【不推荐】ie8- 3项,其他浏览器 2项
let arr3 = [1,2,]; //【不推荐】 ie8- 3项[1, 2, undefined], 其他浏览器[1,2]
}
//3 Array.of()
{
Array.of(2); //[2]
Array.of(2,3); //[2,3]
}
//4 Array.from()
{
Array.from('abc'); //['a', 'b', 'c']
Array.from(312); //[] 数字不可迭代
//用于数组去重,映射函数用法同map
let set = new Set([2,2,3,3])
Array.from(set, (item)=>{
return item * 2
}); //[4, 6]
}
2.2 数组读取
-
数组是经过优化的对象,访问速度比一般对象快;
-
数组索引范围:0~2^32 -2。
-
数组索引,是特殊的对象属性。数字索引,会转化为字符串,进行访问。可以为数组自定义属性名。但只有在索引范围的属性名,才是数组索引,才会影响数组长度。
-
可通过控制数组长度,增删数组
let arr = [1,2]
//字符串索引 == 数字索引
arr[1]; //2
arr['1']; //2
//数组为特殊的对象,可自定义属性
//在索引范围的属性值,为索引,改变数组长度
arr[3] = 3; // arr: [1,2,,3] | arr.length: 4
//不再索引范围的,不改变数组长度
arr['key'] = 'value'; //arr=[1,2,,3,{key: 'value'}] | arr.length: 4
2.3 数组方法
2.3.1 修改原数组
-
栈方法( last in first out) :push, pop
-
队列方法(first in first out):unshift, shift
-
操作方法-数组删除/插入/替换:splice
-
重排序方法: reverse, sort
-
填充数组:fill, copyWithin。es6
//push,unshift
{
let arr = [3,4,2];
arr.push(0); //返回新数组长度4, arr = [3,4,2,0]
}
//pop, shift
{
let arr = [3,4,2];
arr.pop(); //返回弹出项, arr = [3,4,2]
}
//splice
//参数:(startIndex, delNum, insertItems)
//startIndex为负时,用this.length相加
//返回包含删除项的数组
//在原数组上进行修改
{
let arr = [1,2,3];
//插入
arr.splice(0,0,3,3);// arr: [3,3,1,2,3],返回[],因删除0项
//删除
arr.splice(0, 3); //arr: [2,3], 返回:[3,3,1]
//替换:先删除,再插入
arr.splice(0,1,5); //arr: [5,3], 返回: [2]
//warning
arr.splice(1); //[2,3]指定startIndex,但未指定删除数量时,删除到末尾
}
//reverse, sort
//修改并返回原数组
{
let arr = [3,4,2];
let arr2 = arr.reverse(); //arr = [3,4,2], 返回值同arr
let arr3 = arr.sort(); //arr=[2,3,4],sort默认按照升序排列
console.log(arr === arr2, arr === arr3); //true, true
/*arr.sort(compareFn),可以接受一个比较函数,比较Fn两个参数
如果第1个参数应位于第2个参数前,返回负数
如果第1个参数应位于第2个参数后,返回正数
如果两个参数相等,返回0
==》返回负数和0,不动;返回正数,前后两项交换位置。
*/
//升序
function compare(val1, val2){
if(val1 < val2){
return -1;
}else if(val1 > val2){
return 1;
}else{
return 0;
}
}
//简化
function compare(val1, val2){
return val1 - val2;
}
eg:
let obj = [{No: 3, name: 'melon'}, {No: 2, name: 'strawberry'}]
obj.sort((item1, item2)=>{
return item1.No - item2.No;
});
console.log(obj); //[{No: 2, name: 'strawberry'}, {No: 3, name: 'melon'}]
}
//fill
//参数:(val, startIndex, endIndex)
//1. start 默认为0;end 默认为 this.length。 fill替换的对象为this。
//2. start、end 为负数时。用this.length 相加。start < end时,不操作。
// 修改并返回原数组
{
let arr = [1,2,3];
arr.fill(5); //[5,5,5]
arr.fill(6,1); //[5,6,6]
arr.fill(7,1,2); //[5,7,6]
let arr2 = arr.fill(8, -2, -1); //[5,8,6]
console.log(arr === arr2); //true
}
//copyWithin
//参数:(pasteStart, copyStart, copyEnd)
//参数规律同 fill
//修改并返回数组
{
let arr = [1,2,3,4];
let arr2 = arr.copyWithin(0,2); // [3,4,3,4]
arr.copyWithin(-2,1,3); //[3,4,4,3] pasteStart:-2 + arr.length
arr.copyWithin(1); //[3,3,4,4] copyStartmore从0开始
console.log(arr === arr2); //true
}
//fill vs copyWithin
//fill: 填充数组值来源于外部
//copyWithin: 填充数组与元素来源于本数组
2.3.2 不修改原数组的 :
- 数组转换方法:
-
转化为字符串:toString(), toLocaleString(), join,
-
返回数组:valueOf()
let arr = [3,4,undefined,null];
//toString, toLocaleString(), join
//undefined, null 会被转化为空字符串
{
arr.toString(); //返回'3,4,,'
arr.join('-'); //返回'3-4--'
arr.join(); //返回'3,4,,'
}
//valueOf 返回数组
//valueOf结果指向arr引用地址
let arr2 = arr.valueOf(); // 返回[3,4,undefined,null]
{
let arr = [];
let arr1 = arr.valueOf();
arr.push(1);
console.log(arr); //[1]
console.log(arr1); //[1]
}
- 操作方法:concat、slice
//concat
{
let arr = [1]
let arr2 = arr.concat(2); //[1,2]
let arr3 = arr.concat([3,3]); //[1,3,3]
}
//slice
{
let arr = [3,4,undefined,null];
let arr5 = arr.slice(); // [3,4,undefined,null]
let arr6 = arr.slice(1); //[4,undefined,null]
let arr7 = arr.slice(1,3); //[4,undefined],不包括结束位置index
let arr8 = arr.slice(1, -1); //等价于arr.slice(1, arr.length + (-1))
}
//slice截取数组,原数组中的引用数据类型,只拷贝了引用地址
{
let obj = {a: 1};
let arr = [];
let arr1 = arr.slice();
arr.push(obj); //arr: [{a:1}]
let arr2 = arr.slice(); //[{a:1}]
obj.a = 2;
console.log(arr); //[{a:2}]
console.log(arr2); //[{a:2}]
console.log(arr1); //[]
}
- 位置方法:
-
indexOf() 、lastIndexOf()
-
返回数组中给定元素的第一个索引。
-
找不到返回-1。
-
-
find()、findIndex() 两个参数:回掉函数、this指向。 指定条件 检索数组。 es6
-
find返回第一个符合条件的元素。找不到返回undefined。
-
findIndex 返回第一个符合条件的值的索引。找不到返回-1
-
let arr = [1,2,3];
//indexOf() ,lastIndexOf()
{
arr.indexOf(2); //'1'
arr.lastIndexOf(2); //'3'
arr.indexOf(5); //-1
}
//find, findIndex
{
arr.find(item => item > 2); //3
arr.find(item => item > 5); //undefined
arr.findIndex(item => item > 2); //2
arr.findIndex(item => item > 5); -1
}
-
迭代方法(ES5):均不修改原数组。每一项上调用的函数有3个参数—迭代项、该项的位置、数组本身。
-
every、some: 返回布尔型
-
filter、map:返回数组。
-
forEach: 无返回值。作用同for。按顺序遍历。
-
let arr = [1,2,3]
//every——检测是否所有项都满足条件
let everyRes = arr.every((item, index, arr)=>{
console.log(this)
return item > 2;
});
everyRes; //false
//some——检测是否存在满足条件的项
let someRes = arr.some((item,index, arr)=>{
return item > 2;
});
someRes; //true
// filter——筛选出符合条件的项
let filterRes = arr.filter((item, index, arr)=>{
return item >1;
});
filterRes; //[2,3]
//map——将return结果组成新数组
let mapRes = arr.map((item, index, arr)=>{
return item * 2;
});
mapRes; //[2,4,6]
//forEach,用途相当于for
arr.forEach((item, index, arr)=>{
console.log(item)
})
-
归并方法:reduce、reduceRight
-
参数:
-
接受2个参数。每一项上调用的函数、作为归并初始值。
-
函数有4个参数,前一个值(prev)、当前值(cur)、当前项的索引(index)、该数组。
-
有初始值时,第一次遍历,prev为归并初始值,cur为第一项,index为0;迭代arr.length次。
-
无初始值时,第一次遍历,prev为第0项,cur为第2项,index为1。迭代arr.length - 1次。
-
-
-
reduce:从第一项开始
-
reduceRight:从最后一项开始
-
let arr = [1,2,3]
//迭代3次,从第1项开始
let reduceRes1 = arr.reduce((prev, cur, index, arr)=>{
console.log(index);
return prev + cur;
}, 0);
//index 0
//index 1
//index 2
//reduceRes1 6
//迭代2次,从第2项开始
let reduceRes2 = arr.reduce((prev, cur, index, arr)=>{
console.log(index);
return prev + cur;
});
//index 1
//index 2
//reduceRes1 6
Q:检测数组中是否存在某元素的方法:
A:indexOf、lastIndexOf、some、find、findIndex
2.4 类数组对象
2.4.1 类数组特点
-
有length属性。
-
有可转化为正整数的索引,且索引 < 2^32 - 1。
-
只能调用数组的某些方法:
-
3种经典类数组,可用forEach遍历法
-
自定义类数组,不能用forEach遍历。
-
上述两种,均可用for循环遍历。
-
slice、splice、indexOf……不适用容。可用Array.from()转化为真数组,再调用数组API。
-
//类数组1, domNodes
{
let nodes = document.querySelectorAll('div');
Array.isArray(nodes); //false
}
//类数组2,Arguments
{
function fn(arguments){
Array.isArray(arguments); //false
}
fn();
}
//类数组3,jqNOdes
{
Array.isArray($('div')); //false
}
//创建一个类数组,不可使用
{
let obj = {'1': 'a', '2': 'b', 'k1': 'c'};
obj.length = 2;
for(let i = 0; i < obj.length; i++){
console.log(obj[i]);
}
obj.forEach(()=>{}); //报错
obj.map(()=>{})
let arr = Array.from(obj);
console.log(arr); //[undefined, "a"] 不存在项,用undefined补上
}
2.4.2 类数组转换
-
遍历类数组,逐项push进一个数组中。代码较多,不简洁。且必须要有length属性。
-
Array.prototype.slice.call()。 实用。不够直观。
-
Array.from()。直观,能转化所有可迭代对象
let obj = {length: 3};
//遍历类数组
{
function makeArray(arrayLike){
let result = [];
for(let i = 0; i < arrayLike.length; i++){
result.push(arrayLike[i])
}
return result;
}
makeArray(obj); // [undefined, undefined, undefined]
}
//Array.prototype.slice.call()
{
function makeArray(arrayLike){
return Array.prototype.slice.call(arrayLike);
}
makeArray(obj); //[empty × 3]
}
//Array.from()
{
function makeArray(arrayLike){
return Array.from(arrayLike);
}
makeArray(obj); //undefined, undefined, undefined]
}
2.5 定型数组
(看了一边,用的时候,再过一遍)
-
专门用于处理数值类型。为JS提供快速的按位运算。
-
不可修改长度。
-
适用数组方法。除了修改原数组的方法和concat。因concat会混乱数据类型,不符合定型数组初衷。
-
类型包括:
-
Int8Array、Uint8Array、Uint8ClapedArray
-
Int16Array、Uint16Array
-
Int32Array、Uint32Array
-
Float32Array、Float32Array
-
创建定型数组3中方法:
-
数组缓冲区+ 视图缓冲区+set进数据
-
new Int8Array()
-
……用到时,再了解。
tips:
- js数字用 64bit == 8 byte 存储一个浮点数;