以下将对
Array.prototype
上的方法进行整理,es5中数组遍历的方法在 数组扩展方法(一)可以查看
会改变原始数组
以下方法都在Array.prototype
原型上
- push 数组尾部插入元素
- shift 数组首部删除元素
- unshift 向数组首部添加元素
- pop 数组尾部删除
- reverse 反转数组
- splice 删、插、替换数组
- sort 数组排序
- toString 数组转换为字符串
不会改变原数组
以下方法都在Array.prototype
原型上
indexOf 获取元素索引值
lastIndexOf 获取元素索引值
conat 拼接数组
slice 截取数组
join 数组按指定符号转为字符串
工具方法
Array.prototype.indexOf
indexOf
的英文意思为索引值为。
Array.prototype.indexOf
:返回在数组中可以找到给定元素的第一个索引。
indexOf
方法的注意事项:
indexOf
方法使用的是===
全等运算。- 注意是指定元素在数组中第一次出现的索引值。
- 如果指定元素不存在的话,返回
-1
。 - 返回值是指定元素在数组中第一次出现的索引值,不存在时返回
-1
。 - 参数问题:
searchElement
:指定查找的元素。fromIndex
:开始查找的位置。如果该索引值大于数组长度,意味着不会在数组中查找,返回-1
。如果参数中提供的索引值是一个负值,则意味将其作为数组末尾的一个抵消,即-1
相当于arr.length - 1
,-2
相当于arr.length - 2
。注意:虽然fromIndex
可能是负数,但是查询的顺序依旧是从前往后。如果抵消后的索引值小于0,则整个数组都会被查询,默认值为0。
const array = [2, 9, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
重写indexOf
Array.prototype.myIndexOf = function(){
let arr = this,
len = arr.length,
item = null,
arg1 = arguments[0],
arg2 = arguments[1] || 0,
i = 0;
// fromIndex:开始查找的位置。如果该索引值大于数组长度,意味着不会在数组中查找,返回-1。
// 如果参数中提供的索引值是一个负值,则意味将其作为数组末尾的一个抵消,即-1相当于arr.length - 1,-2相当于arr.length - 2。
// 注意:虽然fromIndex可能是负数,但是查询的顺序依旧是从前往后。如果抵销后的索引值小于0,则整个数组都会被查询,默认值为0。
if(arg2 > len) return -1;
if(!arg1) return -1;
i = arg2 < 0 ? (arg2 + len < 0 ? 0 : arg2 + len) : arg2;
// 这里说明一点,使用for...i...遍历,会遍历出稀松数组,建议使用for...in...遍历
for(i ; i < len ; i++){
if(arr[i] === arg1 ){
return i;
}
if(i === len - 1 && arg1 !== arr[i]){
return -1;
}
}
}
const array = [2, 9, 9];
console.log(array.myIndexOf(2)); // 0
console.log(array.myIndexOf(7)); // -1
console.log(array.myIndexOf(9, 2)); // 2
console.log(array.myIndexOf(2, -1)); // -1
console.log(array.myIndexOf(2, -3)); // 0
Array.prototype.lastIndexOf
lastIndexOf
的英文意思是最后的索引值。
Array.prototype.lastIndexOf
:方法返回指定元素在数组中最后一个索引值。如果不存在则返回-1
。从数组的后面项向前查找,从fromIndex
处开始。
lastIndexOf
需要我们注意的有以下几点:
- 参数的问题
searchElement
:被查找的元素。fromIndex
:从此位置开始逆向查找。默认为数组的长度减1(arr.length - 1 )
,即整个数组都被查找。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,数组仍然会从后向前查找。如果该负值的绝对值大于数组长度,则方法返回-1
,即数组不会被查找。
- 返回值是数组在该元素最后一次出现的索引值,如未找到返回
-1
. lastIndexOf
使用严格相等===
比较searchElement
和数组中元素。
var array = [2, 5, 9, 2];
var index = array.lastIndexOf(2);
// index is 3
index = array.lastIndexOf(7);
// index is -1
index = array.lastIndexOf(2, 3);
// index is 3
index = array.lastIndexOf(2, 2);
// index is 0
index = array.lastIndexOf(2, -2);
// index is 0
index = array.lastIndexOf(2, -1);
// index is 3
重写 lastIndexOf
Array.prototype.myLastIndexOf = function(){
let arr = this,
len = arr.length,
arg1 = arguments[0],
arg2 = arguments[1] || len,
i = 0;
if(!arg1 || Math.abs(arg2) > len) return -1;
// if(arg2 >= len) i = len;
// if(arg2 < 0 ) i = arg2 + len;
// if(0 <= arg2 < len) i = arg2;
i = arg2 >= len ? len : (arg2 < 0 ?(arg2 + len):arg2);
for (i; i >= 0; i--) {
if(arg1 === arr[i]) return i;
if(i == 0 && arg1 !== arr[i]) return -1;
}
}
var array = [2, 5, 9, 2];
console.log(array.myLastIndexOf(2)); // 3
console.log(array.myLastIndexOf(7)); // -1
console.log(array.myLastIndexOf(2, 3)); // 3
console.log(array.myLastIndexOf(2, 2)); // 0
console.log(array.myLastIndexOf(2, -2)); // 0
console.log(array.myLastIndexOf(2, -1)); // 3
比较新颖的示例
使用lastIndexOf
查找到一个元素在数组中所有的索引,并使用push
将所有添加到另一个数组中。
var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
var searchElement = 'a';
var idx = array.lastIndexOf(searchElement);
while(idx !== -1) {
indices.push(idx);
idx = (idx > 0 ? array.lastIndexOf(searchElement, idx - 1) : -1);
}
console.log(indices);
Array.prototype.join
Array.prototype.join
:将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。
join
方法需要我们注意的有以下几点:
- 参数问题:
separator
分隔符,如果需要,将分隔符转换为字符串。如果省略该值,数组元素用,
分隔。如果separator
是空字符串""
,则所有元素之间都没有任何字符
- 返回值是一个数组元素连接的字符串。如果
arr.length
为0,则返回空字符串。 - 如果一个元素是
undefined
或null
,它被转换空字符串。 - 这是数组转为字符串的一种方式。
示例
连接类数组对象。
function f(a, b, c) {
var s = Array.prototype.join.call(arguments);
console.log(s); // '1, a, true'
}
f(1, 'a', true)
undefined/null
被转换为空字符串。
var arr = [undefined, null, 1];
console.log(arr.join()); // ,,1
数组扁平化
join
方法带参数的话,只能将数组扁平化一层
join
方法不带参数的话,直接将数组扁平化
// 带参数的话,只能将数组扁平化一层
console.log([1,[2,[3,4,5]]].join('-')); // 1-2, 3, 4, 5
// 不带参数的话,直接数据扁平化,默认分隔
console.log([1,[2,[3,4,5]]].join()); // 1, 2, 3, 4, 5
重写join方法
Array.prototype.myJoin = function (/*separator*/) {
var t = this,
// 保存数组索引值
index = t.length - 1,
// 分隔符
separator = arguments[0] !== undefined ? arguments[0] : ',',
// 结果字符串
restr = '';
// 遍历需要分割的数组
for (var key in t) {
if (t.hasOwnProperty(key)) {
// 处理undefined和null问题,转为空字符串
if (t[key] === undefined || t[key] === null) {
restr += separator;
continue;
}
// 字符串最后一个separator问题
if (key == index) {
restr += t[key]
return restr;
}
console.log(t[key]);
restr += t[key] + separator;
}
}
}
// 当一个数组被作为文本值或者进行字符串拼接操作时,将会自动调用其 toString 方法。
Array.prototype.toString
Array.prototype.toString
:方法返回一个字符串,表示指定的数组及其元素。
toString
方法需要我们注意的有以下几点:
- 无参数。
- 返回值是一个表示数组所有元素的字符串。
toString 方法描述
Array
对象覆盖了Object
的toString
方法。对于数组对象,toString
方法在内部调用join
方法拼接数组中的元素中并返回一个字符串,其中包含逗号分割的每个数组元素。如果join
方法不可用,或者它不是一个函数,将使用Object.prototype.toString
代替,并返回[object Array]
。
当一个数组被作为文本值或者进行字符串拼接操作时,将会自动调用其 toString 方法。
const arr = [];
arr.join = 1;
console.log(arr.toString());
console.log(Array.prototype.toString.call({join: () => 1})); // 1
数组扁平化
toString
方法能够将多维数组进行扁平化。
console.log(Array.prototype.toString.call([1, 2, 3, 4])); // 1,2,3,4
console.log(Array.prototype.toString.call([[1, 2], [3, 4]])); // 1,2,3,4
Array.from
Array.from()
方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例对象。
Array.from()
需要注意的有以下几点
- 参数问题
arrayLike
:想要转为数组的伪数组对象或可迭代对象。mapFn
:如果制定了该参数,新数组中的每个元素都会执行该回调函数。thisArg
:可选参数,执行回调mapFn
时this
对象。
返回值:一个新的数组实例。
// 下面是一个类似数组的对象,Array.from将它转为真正的数组。
let arrayLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
}
// es6 写法
let arr2 = Array.from(arrayLike) ; // ['a','b','c']
实际应用中,常见的类似数组的对象是 DOM 操作返回的 NodeList 集合,以及函数内部的arguments对象。Array.from都可以将它们转为真正的数组。
let dom = document.querySelectorAll('div');
let domArray = Array.from(dom)
只要是部署了 Iterator 接口的数据结构,Array.from都能将其转为数组。
console.log(Array.from('hello')); // ['h', 'e', 'l', 'l', 'o']
console.log('hello'.__proto__);
let namesSet = new Set(['a','b','b']);
console.log(Array.from(namesSet));
// ['a', 'b']
上面代码中,字符串和 Set 结构都具有 Iterator 接口,因此可以被Array.from转为真正的数组。
如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组。
值得提醒的是,扩展运算符(…)也可以将某些数据结构转为数组。
function foo(){
const arg = [...arguments]
}
[...document.querySelectorAll('div')]
扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。Array.from方法还支持类似数组的对象。所谓类似数组的对象,本质特征只有一点,即必须有length属性。因此,任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换。
console.log(Array.from({length:3}));
// [undefined, undefined, undefined]
上面代码中,Array.from返回了一个具有三个成员的数组,每个位置的值都是undefined。扩展运算符转换不了这个对象。
- 重写from方法
Array.myFrom = function (iteratorObj, callback) {
// this指向
var thisArg = arguments[2] !== undefined ? arguments[2] : window;
var isIterable = iteratorObj[Symbol.iterator] || iteratorObj.hasOwnProperty('length');
// 创建一个数组
var resArr = [];
// 计步器
var index = 0;
if (isIterable) {
if (iteratorObj.hasOwnProperty('length')) {
for (var key in iteratorObj) {
if (typeof callback === 'function') {
key !== 'length' ? resArr[index] = callback.apply(thisArg, [iteratorObj[key], index++]) : '';
}else{
key !== 'length' ? resArr[index++] = iteratorObj[key] : ''
}
}
} else {
for (var value of iteratorObj) {
if (typeof callback === 'function') {
resArr[index] = callback.apply(thisArg, [value, index++]);
}else{
resArr[index++] = value;
}
}
}
index = 0;
}
return resArr;
}