JS学习笔记 (四) 数组进阶

发布于 2021-05-05  667 次阅读


1、基本知识

1、数组是值的有序集合。每个值叫做一个元素,而每个元素在数组中的位置称为索引,以数字表示,以0开始。
2、数组是无类型的。数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类型。数组的元素可以是对象或其它数组。
3、数组是动态的,数组长度可长可短。在创建数组时无须声明一个固定的大小或者在数组大小变化时无须重新分配空间
4、数组可以是稀疏的。数组元素的索引不一定是连续的,它们之间可以有空缺,每个数组都有一个length属性,针对非稀疏数组,该属性就是数组元素的个数,针对稀疏数组,length比实际元素个数要大。
5、JavaScript数组是JavaScript对象的特殊形式。数组索引可以认为是整数的属性名。
6、数组继承自Array.prototype中的属性。它定义了许多的方法,它们对真正的数组和类数组对象都有效。如,字符串、arguments等。

2、操作数组

2.1 创建数组

2.1.1 字面量创建

举个例子:

let empty = [];
let arr1 = [2, 3, 5, 7, 11];
let arr2 = [1.1, true, "a"];
let i = 10;
let arr3 = [i, i + 1, i++, ++i];
let arr4 = [
    [1, { x: 1, y: 2 }],
    [2, { x: 3, x: 4 }],
];
let arr5 = [1, , 3];
let arr6 = [, ,];

2.1.1 构造函数Array( )创建

可以通过new Array()创建数组,如:

let arr1 = new Array(); //相当于[]
let arr2 = new Array(5);
let arr3 = new Array(1, 2, 3, "四", "五", "六");

2.2 读写数组元素

2.2.1 使用[ ]操作符来访问数组中的一个元素。

注意:
1、方括号中是一个返回非负整数值的任意表达式。
2、使用该语法既可以读又可以写数组的一个元素。
3、若数组的索引小于0,则默认将该索引值作为数组中的一个属性。
举个例子:

let a = ["world"];
let value = a[0];
a[1] = 3.14;
i = 2;
a[i] = 3;
a[i + 1] = 4;
a[a[i]] = a[0];
a["10"] = "hi";
a["ten"] = "hoo";
a[-2] = -2;
a[1.11] = 1.11;
console.log(a);

输出结果:
[
  'world',        
  3.14,
  3,
  'world',        
  <6 empty items>,
  'hi',
  ten: 'hoo',     
  '-2': -2,       
  '1.11': 1.11    
]

2.2.2 稀疏数组

1、包含从0开始的不连续索引的数组。
2、可以用Array()构造函数或简单地指定数组的索引值大于当前的数组长度来创建稀疏数组。
举个例子:

let a1 = [, , ,];
let a2 = new Array(4);
console.log(1 in a1, 1 in a2);
a1[10] = 100;
a1[8] = undefined;
for (let a in a1) {
    console.log(a, a1[a]);
}

输出结果:
false false
8 undefined
10 100

2.2.3 数组长度

每个数组都有length属性,表示数组的长度以及数组内元素的个数。

  • 设置为一个小于当前长度的非负整数n时,当前数组中那些索引值大于或等于n的元素将从中删除。
  • 设置为大于其当前的长度,会在数组尾部创建一系列空的区域
  • 可以用Object.defineProperty()让数组的length属性变成只读的。
    举个例子:
let arr = [1, 2, 3];
arr.length = 5;
console.log(arr); // [ 1, 2, 3, <2 empty items> ]

Object.defineProperty(arr, "length", {
    writable: false,
    configurable: false,
});
arr.length = 3;
console.log(arr); // [ 1, 2, 3, <2 empty items> ], 由于设置了数组的length为不可读,所以不能修改数组长度

arr.push(1000);
console.log(arr); // TypeError 由于设置了数组的length为不可读,所以不能修改数组长度

// 修改数组的length属性为只读
Object.defineProperty(arr, "length", { writable: true });

2.2.4 数组元素操作

方法 描述
push 接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度
unshift 在数组头部添加任意个项并返回新数组的长度
pop 从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项
shift 移除数组中的第一个项并返回该项,同时将数组长度减 一
delete 后接要删除的数组元素,数组的长度减一,并返回新数组
join 将数组中所有元素都转化为字符串并连接在一起,返回最后生成的字符串,可以指定一个可选的字符串在生成的字符串中来分隔数组的各个元素。如果不指定分隔符,默认使用逗号。
reverse 将数组中的元素颠倒顺序,返回逆序的数组
sort 将数组中的元素排序并返回排序后的数组,当不带参数调用sort()时,数组元素以字母表顺序排序,若有两个参数,参数的先后顺序决定了数组先后顺序
concat 创建并返回一个新数组,它的元素包括调用concat()的原始数组的元素和concat()的每个参数
slice 返回指定数组的一个片段或子数组,它的两个参数分别指定了片段的开始和结束的位置
splice 当只有一个参数(index)时,表示删除index+1以及后面的所有元素。当有两个参数(index,many)时,表示从index位置开始,删除many个元素。当有多个参数(index,many,item1,item2,item3...itemn)时,表示从index开始,删除many个元素,并添加item1,item2,item3...itemn

举个例子:

let arr = [1, 2, 3, 4, 5, 0, 6];
let arr1 = arr.join("-")
let arr2 = arr.reverse()
let arr3 = arr.sort((a, b) => a - b)
let arr4 = arr.concat(111, [222, 333])
let arr5 = arr.slice(1, 3)
console.log(arr1); // 1-2-3-4-5-0-6
console.log(arr2); // [0, 1, 2, 3, 4, 5, 6]
console.log(arr3); // [0, 1, 2, 3, 4, 5, 6]
console.log(arr4); // [0, 1, 2, 3, 4, 5, 6, 111, 222, 333]
console.log(arr5); // [ 1, 2 ]
let arr = [1, 2, 3]
arr[arr.length] = 4
arr.push(5) //尾部追加
arr.unshift(0)  // 头部追加
console.log(arr) // [ 0, 1, 2, 3, 4, 5 ]

delete arr[1]
console.log(arr) // [ 0, <1 empty item>, 2, 3, 4, 5 ]

arr.pop() // 头部删除
arr.shift() // 尾部删除
console.log(arr); //[ <1 empty item>, 2, 3, 4 ]

arr.splice(1, 2, ...[22, 33])  //从1开始删除2个替换成22,33
console.log(arr); //[ <1 empty item>, 22, 33, 4 ]

arr.splice(1, 0, ...[222, 333]) // 插入
console.log(arr);// [ <1 empty item>, 222, 333, 22, 33, 4 ]

arr.splice(1, 2) // 直接删除
console.log(arr);// [ <1 empty item>, 22, 33, 4 ]

2.2.5 利用原型继承,为数组扩展出插入、删除和替换元素的方法

Array.prototype.remove = function (index, len) {
    // return this.splice(index, len) // 返回已经删除的元素
    this.splice(index, len)
    return this
}
// arr 是要插入的数组
Array.prototype.insert = function (index, arr) {
    this.splice(index, 0, ...arr)
    return this
}
// arr 是要替换的数组
Array.prototype.replace = function (index, arr) {
    this.splice(index, arr.length, ...arr)
    return this
}

let nums = [1, 2, 3, 4, 5]
console.log(nums.remove(1, 3)); // [1,5]
console.log(nums.insert(1, [22, 33, 44])); // [1, 22, 33, 44, 5]
console.log(nums.replace(1, [222, 333, 444])); // [1, 222, 333, 444, 5]

2.2.6 常见的数组遍历方法

方法 描述
for..in.. 遍历数组的索引(即键名)
for..of.. 遍历数组的元素值
Object.keys 返回数组的索引(即键名)组成的数组
Object.value 返回数组的元素值组成的数组

举个例子:

let arr = ["Chinese","Math","English"];
for(let i in arr){
    console.log(i);
}
// 0
// 1
// 2

for(let i of arr){
    console.log(i);
}
// Chinese
// Math
// English

console.log(Object.keys(arr)); // [ '0', '1', '2' ]
console.log(Object.values(arr)); // [ 'Chinese', 'Math', 'English' ]

2.2.7 实例方法

1、ES5定义了9个数组方法来遍历、映射、过滤、检测、简化和搜索数组

方法 描述
forEach() 从头至尾遍历数组,为每个元素调用指定的函数
map() 将调用的数组的每个元素传递给指定的函数,并返回一个数组,它包含该函数的返回值。
fliter() 返回的数组元素是调用的数组的一个子集。传递的函数是用来逻辑判定的:该函数返回true或false
every() 对数组中每一项运行给定函数,如果该函数对每一项返回true,则返回true
some() 对数组中每一项运行给定函数,如果该函数对任意一项返回true,则返回true
reduce() 接受一个累加器函数,在这个函数中迭代数组的所有项,然后返回一个值。从数组的第一项开始,向后遍历到最后一项
reduceRight() 接受一个累加器函数,在这个函数中迭代数组的所有项,然后返回一个值。从数组的最后一项开始,向前遍历到第一项
indexOf() 搜索某个指定的字符串值在字符串中首次出现的位置,从前往后查找。返回找到的第一个元素的索引,如果没有找到就返回-1
lastIndexOf() 搜索某个指定的字符串值在字符串中最后一次出现的位置,从后向前查找。返回找到的第一个元素的索引,如果没有找到就返回-1

举个例子:

let arr=[1,2,3,4,5]
let reducer=(total,current)=>total+current;
let total=arr.reduce(reducer)
console.log(total); // 15
let strs = "好好学习天天向上"
console.log(strs.indexOf("好")); // 0
console.log(strs.lastIndexOf("好")); // 1

2、ES6新增了8个方法用于对ES5的补充

方法 描述
copyWith( ) 在当前数组内部将指定位置的元素复制到其他位置(会覆盖原有元素),返回当前数组。
find( ) 用户找出第一个符合条件的数组元素(或其索引)
findIndex( ) 用户找出第一个符合条件的数组元素(或其索引)
fill( ) 使用给定值填充一个数组
entries( ) 返回所有成员键值对所组成的数组的遍历器对象
keys( ) 返回键名的遍历器对象
values( ) 返回键值的遍历器对象
includes( ) 判断数组中是否包含给定的值,与字符串的includes方法类似。

举个例子:

let arr = ["小明","男生",16]
for(let i of arr.keys()){
    console.log(i);
}
// 0
// 1
// 2

for(let i of arr.values()){
    console.log(i);
}
// 小明
// 男生
// 16

for(let i of arr.entries()){
    console.log(i);
}
// [ 0, '小明' ]
// [ 1, '男生' ]
// [ 2, 16 ]

2.2.8 构造函数方法

1、Array.from( ),将类似数组的对象和可遍历的对象转化成真正的数组,如HTML中的li标签。
举个例子:

<body>
    <ul id="list-nums">
        <li>100</li>
        <li>200</li>
        <li>300</li>
    </ul>
</body>
<script>
    let lis = document.querySelectorAll("#list-nums li")
    console.log(lis);
    let items = Array.from(lis,function(item){
        return item.textContent;
    })
    console.log(items);
</script>

输出结果:
NodeList(3) [li, li, li]
test01.html:59 (3) ["100", "200", "300"]

2、Array.of( ),将一组值转换为数组
举个例子:

let arr = [1, 2, 3, 4, 5, 6]
let nums = Array.of(...arr, 7, 8, 9);
console.log(nums); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9]

活的像诗一样