共计 9785 个字符,预计需要花费 25 分钟才能阅读完成。
前言
数组是我们平时编码中必不可少的一个重要,无论是数据的处理还是数据的传递,它都起到了至关重要的作用。无论是老版的 JavaScript 还是 ES6 都提供了大量的方法让我们来对数组进行处理。本文主要介绍 Array 对象的本质和它的相关属性,方法。
Array
原型链示意图
分两个方向来分析 Array
1 JavaScript 的原生对象 Array
1-1 Array 有哪些属性和方法。
按 f12 打开控制台输入【Array.】你会发现侧边出现了很长的一串的属性和方法的补全提示,这些属性和方法到底哪些是可用的又有哪些是 Array 对象本身的呢?我们可以试验一下。
console.log(Array.length);
console.log(Array.name);
console.log(Array.from);
console.log(Array.isArray);
console.log(Array.of);
console.log(Array.apply);
console.log(Array.bind);
console.log(Array.constructor);
console.log(Array.toString);
console.log(Array.hasOwnProperty);
console.log(Array.isPrototypeOf);
console.log(Array.toLocaleString);
console.log(Array.valueOf);
console.log(Array.arguments);
console.log(Array.call);
console.log(Array.caller);
打印结果
除了最后的 3 个属性报错其他的属性或方法全部被打印出来,但是这些不一定就是 Array 的本身的属性和方法。首先 Array 作为函数实际上可以看做是通过 new Function() 创建的,所以它继承了 Function 原型上的属性和方法,而 Function.prototype 作为对象是可以继承 Object 原型上的属性和方法。所以 Array 也继承了 Object 原型上的属性和方法。
我们可以通过 Object 的 hasOwnProperty 方法来判断哪些才是真正的属于 Array 对象的属性和方法。
console.log(Array.hasOwnProperty(“length”));
console.log(Array.hasOwnProperty(“name”));
console.log(Array.hasOwnProperty(“from”));
console.log(Array.hasOwnProperty(“isArray”));
console.log(Array.hasOwnProperty(“of”));
console.log(Array.hasOwnProperty(“apply”));
console.log(Array.hasOwnProperty(“bind”));
console.log(Array.hasOwnProperty(“constructor”));
console.log(Array.hasOwnProperty(“toString”));
console.log(Array.hasOwnProperty(“hasOwnProperty”));
console.log(Array.hasOwnProperty(“isPrototypeOf”));
console.log(Array.hasOwnProperty(“toLocaleString”));
console.log(Array.hasOwnProperty(“valueOf”));
// 打印结果
true
true
true
true
true
false
false
false
false
false
false
false
false
通过上面的分析我们知道了 Array 作为对象其实只拥有 length,name 两个属性和 form,isArray,of 这 3 个方法。
注意:这里还有几个继承的方法和属性我没有一一列举出来更多属性可见详情 Array
1-2 属性和方法使用
1-2-1 length 属性返回 Array 对象的长度。
这里的 length 属性只是 Array 本身的 length 属性,其值为 1。
1-2-2 name 属性返回 Array 对象名称。
与 length 属性一样,其值为 ”Array”。
1-2-3 form 方法,转换其它类型的数据并返回一个新的数组。
参数 1:要转换的数据
将类数组对象转换为真正数组:
let fakeArray = {
0: “csz”,
1: “women”,
2: “21”,
3: [“say”,”sleep”,”drink”],
‘length’: 4
}
console.log(Array.from(fakeArray))
// [“csz”, “women”, “21”, [“say”,”sleep”,”drink”]]
注意:要将一个类数组对象转换为一个真正的数组,必须具备以下条件:
该类数组对象必须具有 length 属性,用于指定数组的长度。如果没有 length 属性,那么转换后的数组是一个空数组。
该类数组对象的属性名必须为数值型或字符串型的数字。如果不是转成的数组的值全是 undefined。
将 Set 结构的数据转换为真正的数组:
let arr = [1,2,3,4,5,5,6]
let set = new Set(arr);
console.log(Array.from(set));
// [1,2,3,4,5,6]
将字符串转换为数组:返回分割字符串形成的数组。
let str = ‘foo’;
console.log(Array.from(str));
// [“f”,”o”,”o”]
Array.from 参数是一个真正的数组:返回原数组。
console.log(Array.from([1,2,3,4,5]))
// [1,2,3,4,5]
参数 2:回调函数
let arr = [1, 2, 3, 4, 5];
console.log(Array.from(arr, item => item + 1));
// [2,3,4,5,6];
1-2-4 isArray 方法用于判断一个对象是否为数组。
let arr = [1,2,3];
let str = “123”;
let num = 123;
Array.isArray(arr);
Array.isArray(str);
Array.isArray(num);
// 打印结果
true
false
false
1-2-5 of 方法用于创建一个新的数组。
let arr = Array.of(1);
let arr2 = Array.of(2);
let arr3 = Array.of(1,2,3,4);
//
[1]
[5]
[1,2,3,4]
注意:form 和 of 都是 ES6 新增的方法。
2 作为函数调用
2-1 规范
当数组作为函数调用而不是构造函数调用时,它会创建并初始化一个新的数组对象。因此当 Array(…) 和 new Array(…) 接收同样的参数时,它们是相同的。
let arr = Array(1,3);
// [1,3];
let arrs = new Array(1,3);
// [1,3];
2-2 传参
传入多个数值或者多个其它类型的数据的时候,直接以【,】分割这些数据形成一个新的数组。
let arrStr = new Array(“1”, “2”);
//[“1″,”2”]
let arrObj = new Array({name: “csz”}, {“age”: 12});
//[{name: “csz”}, {age: 12}]
传入一个 0 到 232-1 之间的整数,会把它识别为创建的数组的长度,会创建一个这个以这个整数位长度,每一项都是 undefined 的数组。
let arr = new Array(3);
console.log(arr[0], arr[1], arr.length);
// undefined, undefined, 3
ES6 新增的 of 方法没有第二种传参方式。
2-3 实例方法
不管是通过字面量还是 new Array 亦或者是 Array.of() 创建的实例对象,它们的__proto__属性都是指向了 Array 的原型对象,就继承了原型对象上的属性和方法。
ES5 原有方法 Array.prottotype.
2-3-1 forEach()
数组调用该方法,每一个元素执行 callback 一次。
2 个参数:
callback 接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,forEach 方法被调用的数组。
thisArg
执行 callback 函数时使用的 this 值。
如果 thisArg 参数有值,则每次 callback 函数被调用的时候,this 都会指向 thisArg 参数上的这个对象。如果省略了 thisArg 参数, 或者赋值为 null 或 undefined,则 this 指向全局对象。
let arr = [1, 2, 3];
arr.forEach(function (v, i, arr) {
console.log(v);
arr.push(1);
});
console.log(arr);
// 打印结果
1
2
3
[1,2,3,1,1,1]
2-3-2 shift()
方法从数组中删除第一个元素,并返回该元素的值。此方法更改原有数组。
let arr = [1, 2, 3];
console.log(arr.shift()); // 1
console.log(arr); // [2,3]
2-3-3 pop()
方法从数组中删除最后一个元素,并返回该元素的值。此方法更改原有数组。
let arr = [1, 2, 3];
console.log(arr.pop()); // 3
console.log(arr); // [1,2]
2-3-4 unshift()
方法将一个或多个元素添加到数组的开头,并返回该数组的新长度。此方法更改原有数组。
一个参数
elementN 要添加到数组开头的元素。
let arr = [1, 2, 3];
console.log(arr.unshift(4, 5)); // 5
console.log(arr); // [4,5,1,2,3]
2-3-5 push()
方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。此方法更改原有数组。
一个参数
elementN 要添加到数组开头的元素。
let arr = [1, 2, 3];
console.log(arr.push(4, 5)); // 5
console.log(arr); // [1,2,3,4,5]
2-3-6 splice()
方法通过删除现有元素和 / 或添加新元素来修改数组, 并以数组返回原数组中被修改的元素。此方法更改原有数组。
3 个参数:
start指定修改的开始位置(从 0 计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从 - 1 计数);如果负数的绝对值大于数组的长度,则表示开始位置为第 0 位。
deleteCount
整数,表示要移除的数组元素的个数。
如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
如果 deleteCount 被省略,则其相当于 (arr.length – start)。
item1, item2, … 要添加进数组的元素, 从 start 位置开始。如果不指定,则 splice() 将只删除数组元素。
let arr = [1, 2, 3, 4, 5];
// start 超过数组长度,且没有添加新的元素
console.log(arr.splice(5)); //[]
console.log(arr); //[1,2,3,4,5]
// start 不超过数组长度,且没有添加新的元素
let arr1 = [1, 2, 3, 4, 5];
console.log(arr1.splice(0, 2)); //[1,2]
console.log(arr1); //[3,4,5]
// start 不超过数组长度,删除个数为 0 或者负数,添加新的元素
let arr2 = [1, 2, 3, 4, 5];
console.log(arr2.splice(0, 0, 1)); // []
console.log(arr2); // [1,1,2,3,4,5]
// start 为负数且负数绝对值不超过数据长度,添加新的元素
let arr3 = [1, 2, 3, 4, 5];
console.log(arr3.splice(-3, 1, “a”)); //[3]
console.log(arr3); //[1,2,”a”,4,5]
// start 为负数且负数绝对值超过数据长度,添加新的元素
let arr4 = [1, 2, 3, 4, 5];
console.log(arr4.splice(-6, 1, “a”)); //[3]
console.log(arr4); //[“a”,2,3,4,5]
2-3-7 slice()
方法通起止索引截取数组中的元素,返回一个新的数组对象。原始数组不会被改变。
2 个参数:
start
指定截取的开始位置(从 0 计数)。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取。
省略就从 0 开始截取。
没有 end 就从开始位置截取,剩下的所有数组中的元素。
end
在该索引处结束提取原数组元素(从 0 开始)。
slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin,但不包含 end)。
let arr = [1, 2, 3, 4, 5];
// start 为正数,没有 end
console.log(arr.slice(1)); //[2,3,4,5]
console.log(arr); //[1,2,3,4,5]
let arr1 = [1, 2, 3, 4, 5];
// start 为正数,有 end
console.log(arr1.slice(1, 3)); //[2,3]
console.log(arr1); //[1,2,3,4,5]
let arr2 = [1, 2, 3, 4, 5];
// 两个参数都是负数
console.log(arr2.slice(-3, -1)); //[3,4]
console.log(arr2); //[1,2,3,4,5]
2-3-8 join() 方法
将一个数组的所有元素按指定分隔符连接成一个字符串并返回这个字符串,不改变原数组。
一个参数
separator
指定一个字符串来分隔数组的每个元素。
默认为 “,”。
如果 separator 是空字符串 (“”),则所有元素之间都没有任何字符。
let arr = [1, 3, 4];
console.log(arr.join(“”)); // “134”
console.log(arr.join(“-“)); // “1-3-4”
// “1”;
2-3-9 reverse()
方法将数组中元素的位置颠倒。改变原数组。
let arr = [1,2,3,4,5];
console.log(arr.reverse()); // [5, 4, 3, 2, 1]
console.log(arr) // [5, 4, 3, 2, 1]
2-3-10 concat() 方法
用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
let arr = [1, 3, 4];
let arr1 = [1, 2, “a”];
console.log(arr.concat(arr1));
// [1,3,4,1,2,”a”];
2-3-11 indexOf() 方法
返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回 -1。
2 个参数:
searchElement 要查找的元素。
fromIndex
开始查找的位置。默认为 0
- 1 代表数组中的最后一个元素,依次为起点往前查找。
let arr = [1, 2, 3];
console.log(arr.indexOf(1)); // 0
console.log(arr.indexOf(5)); // -1
2-3-12 lastIndexOf() 方法
返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从传参的索引处开始。
2 个参数:
searchElement 要查找的元素。
fromIndex
从此位置开始逆向查找。默认为数组的长度减 1,即整个数组都被查找。
如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。
即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
let arr = [1, 2, 3, 1];
console.log(arr.lastIndexOf(1, 0)); // 3
console.log(arr.lastIndexOf(1, 2)); // 0
2-3-13 toString()
返回一个数组元素组成的字符串,以逗号分隔。不改变原数组。
let arr = [1, 2, 3];
console.log(arr.toString()); // “1,2,3”
console.log(arr); // [1, 2, 3]
2-3-14 map()
数组调用该方法,callback 会循环遍历数组一次,最后返回一个每一次循环遍历处理后的结果组成的新数组。不会改变原有数组。
2 个参数:
callback 接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,map 方法被调用的数组。
thisArg
执行 callback 函数时使用的 this 值。
如果 thisArg 参数有值,则每次 callback 函数被调用的时候,this 都会指向 thisArg 参数上的这个对象。如果省略了 thisArg 参数, 或者赋值为 null 或 undefined,则 this 指向全局对象。
let obj = {
name: ‘csz’,
say: function () {
console.log(this.name);
}
}
let arr = [1, 2];
let map1 = arr.map(function (value, index, array) {
console.log(value, index, array);
this.say();
return value = value + 2;
}, obj);
console.log(map1, arr);
// 打印结果
1 0 [1, 2]
csz
2 1 [1, 2]
csz
[3, 4] [1, 2]
因为箭头函数内的 this 指向是保持不变的,所以当要使用 thisArg 参数时,不要使用箭头函数。
2-3-15 every()
方法测试数组的所有元素是否都通过了指定函数的测试。全部通过返回 true, 否则返回 false。
2 个参数:
callback 用来测试每个元素的函数,接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,every 方法被调用的数组。
遍历数组的每一个元素执行 callback,只要有一个元素在执行 callback 的时候 return false,every 方法停止执行返回 false。
thisArg 执行 callback 时使用的 this 值。(使用方法用 map() 一致)
let arr = [1, 3, 5, 7, 9, 10];
let arr1 = [1, 3, 5, 7];
console.log(arr.every((v, i, array) => {
return v % 2 !== 0;
}));
console.log(arr1.every((v, i, array) => {
return v % 2 !== 0;
}));
// 打印结果
false
true
2-3-16 some()
方法测试数组中的某些元素是否通过由提供的函数实现的测试。有一个通过返回 true, 全部不通过返回 false。
2 个参数:
callback 用来测试每个元素的函数,接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,every 方法被调用的数组。
遍历数组的每一个元素执行 callback,只要有一个元素在执行 callback 的时候 return true,every 方法停止执行返回 true。
thisArg 执行 callback 时使用的 this 值。(使用方法用 map() 一致)
let arr = [1, 3, 5, 7, 9, 21, 2, 4, 6];
console.log(arr.some((v, i, array) => {
return v > 10;
}));
// true
2-3-17 filter()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
2 个参数:
callback 用来测试每个元素的函数,接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,filter 方法被调用的数组。
遍历数组的每一个元素执行 callback,把满足条件的元素返回最后集合组成一个新的数组。
thisArg 执行 callback 时使用的 this 值。(使用方法用 map() 一致)
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let newArr = arr.filter((v, i, array) => {
return v % 2 === 0;
});
console.log(newArr);
// [2,4,6,8]
ES6 新增方法 Array.prottotype.
2-3-18 includes() 方法
用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。
2 个参数:
searchElement 需要查找的元素值。-
fromIndex 从该索引处开始查找 searchElement。如果为负值,则按升序从 array.length – fromIndex 的索引开始搜索。默认为 0。
let arr = [1, 2, 3];
console.log(arr.includes(1)); // true
console.log(arr.includes(5)); // false
2-3-19 find()
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
2 个参数:
callback 用来测试每个元素的函数,接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,find 方法被调用的数组。
遍历数组的每一个元素执行 callback,返回第一个满足条件的元素。
thisArg 执行 callback 时使用的 this 值。(使用方法用 map() 一致)
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let newArr = arr.find((v, i, array) => {
return v > 5;
});
console.log(newArr);
// 6
2-3-20 findIndex()
方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回 -1。
2 个参数:
callback 用来测试每个元素的函数,接受 3 个参数。
currentValue,数组中正在处理的当前元素。
index,数组中正在处理的当前元素的索引。
array,findIndex 方法被调用的数组。
遍历数组的每一个元素执行 callback,返回第一个满足条件的元素的索引。
thisArg 执行 callback 时使用的 this 值。(使用方法用 map() 一致)
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let newArr = arr.findIndex((v, i, array) => {
return v > 5;
});
console.log(newArr);
// 5
2-3-21 fill()
方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。改变原数组。
3 个参数:
start 用来填充数组元素的值。
start 起始索引,默认值为 0。
end 终止索引,默认值为 this.length。
let arr = [1, 2, 3, 4, 5, 6];
arr.fill(“csz”, 1, 4);
console.log(arr);
// [1, “csz”, “csz”, “csz”, 5, 6]
还有几个方法相关介绍我还没有理的很清楚,这里先不贴了。等后续会加上。