开始
之前三节总结了15个js 中常用数组方法和原理实现,下面继续按照MDN上介绍总结和整理5个方法。
数组方法
Array.prototype.reverse()
作用
reverse() 方法将数组中元素的位置颠倒,并返回该数组。数组的bunn第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
应用
console.log([1,2,3,4,5].reverse()) //[5,4,3,2,1]- 也可以用于类数组元素
const a = {0: 1, 1: 2, 2: 3, length: 3};
Array.prototype.reverse.call(a)
console.log(a); // { '0': 3, '1': 2, '2': 1, length: 3 }
实现
思路
- 在数组的原型上定义方法
- 会改变原数组,不能改变新数组,所以必须在数组本身操作,不能返回新数组。
- 采用取中值,对称替换的方法。
代码实现
Array.prototype._reverse=function(){
if(this.length===0)
{
return this;
}
//一分为2
// 1,2,3,4,5 需要 2,4换位置,
let left=Math.floor(this.length/2)-1; //左侧索引
let y=this.length%2;//取个余数(长度是偶数就是0,否则是1)
let right=left+y+1; //右侧索引
while(left>=0 && right<this.length)
{
//交换位置
let value=this[left];
this[left]=this[right];
this[right]=value;
//指针左移
left--;
//指针右移
right++;
}
return this;
}
测试
同样也能获得相同的结果。
console.log([1,2,3,4,5]._reverse()) //[5,4,3,2,1]
const a = {0: 1, 1: 2, 2: 3, length: 3};
Array.prototype._reverse.call(a)
console.log(a); // { '0': 3, '1': 2, '2': 1, length: 3 }
Array.prototype.slice()
作用
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
应用
begin和end可正可负,如果为负数时候与数组长度相加。
- 普通数组
console.log([1,2,3,4,5].slice(2)) //[3,4,5]
console.log([1,2,3,4,5].slice('s')) //[1,2,3,4,5]
console.log([1,2,3,4,5].slice('s','d')) //[]
console.log([1,2,3,4,5].slice(2)) //[3,4,5]
console.log([1,2,3,4,5].slice(0,2)) //[1,2]
console.log([1,2,3,4,5].slice(0,-2))//[1,2,3] 相当于 (0,3)
console.log([1,2,3,4,5].slice(-2,-1))//[4] 相当于 (3,4)
- 应用于类数组对象
可以arguments 转为数组
function get() {
return Array.prototype._slice.call(arguments,1);
}
console.log(get(1, 2, 3)); // [1, 2, 3]
实现
思路
- 在数组原型上定义。
- begin 和end 如果不能转为合法数字,begin默认为0,end默认为数组长度
- begin 和end 为负数要与数组长度相加,取值时候不包括end,比如 (0,3) 取索引0,1,2。
- 不能改变原数组,要返回新数组。
代码实现
Array.prototype._slice=function(start,end){
//取整
start=Math.floor(start-0)||0;
end=Math.floor(end-0)||this.length;
if(start>this.length-1) return [];
if(end>this.length) end=this.length;
//为负数与长度相加,与长度相加后仍未负数 置为0
start=start<0?(start+this.length>0?start+this.length:0):start;
//与长度相加后仍未负数 置为0
end=end<0?(end+this.length>0?end+this.length:0):end;
let arr=[];
for(let i=start;i<end;i++)
{
arr.push(this[i])
}
return arr;
}
测试
同样可以实现相同的功能。
console.log([1,2,3,4,5]._slice(2)) //[3,4,5]
console.log([1,2,3,4,5]._slice(0,2)) //[1,2]
console.log([1,2,3,4,5]._slice(0,-2))//[1,2,3]
console.log([1,2,3,4,5]._slice(-2,-1))//[4]
Array.prototype.some()
作用
some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。与every 方法对应。
实现
代码
与every差不多,不再多言。
Array.prototype._every=function (callback,thisArg) {
if(typeof callback!='function')
{
throw new TypeError('callback is not a function')
}
let target=this,res=false;
let context=thisArg ||this;
for(let i=0;i<target.length;i++)
{
//有一项满足就返回true
if(callback.call(context,target[i],i,target))
{
return true;
}
}
return res;
}
Array.prototype.splice()
作用
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
三个参数 [start.deleteCount,...args]
- start :起始索引,可为负数
- deleteCount 删除元素的个数,默认为start索引之后的全部移除。
- ...args 其余参数 表示替换项
应用
也是数组中一个很重要的API
- 移除数组某几项,最常见的就是根据索引删除元素
var a=[1,2,3,4,5,6]
console.log(a.splice(1,1)) //[ 1]
console.log(a);//[ 1, 3, 4, 5, 6 ]
- 替换元素
var a=[1,2,3,4,5,6]
console.log(a.splice(1,1,10)) //[2]
console.log(a); [1, 10, 3, 4, 5, 6]
实现
思路
- 在数组的原型上定义方法。
- 由于改变原数组但是不能出现 this=xxx;这样会报错,所以只能原数组上操作。
- 举例:[1,2,3,4,5] => (1,2,3,4) 三部分 [1],[2,3]移除 返回的结果, 剩下 [4,5],然后插入[1](start 之前的) [3,4] (替换部分)
- 方法的返回值,所以要将将移除的元素存入 res,返回。
代码实现
Array.prototype._splice=function(){
let params=Array.prototype.slice.call(arguments);
let start=params.shift();
let deleteCount=params.shift();
//取整
start=Math.floor(start-0)||0;
if(start<0)
{
start=this.length+start;
}
if(start>this.length-1) return [];
//不是合法数字 默认未删除
deleteCount=Math.floor(deleteCount-0)|| this.length-start;
//小于0 默认为0
deleteCount<0?0:deleteCount;
deleteCount>this.length-start?this.length-start:deleteCount;
let i=0,startArr=[],endArr=[],res=[],len=this.length;
for(let i=0;i<start+deleteCount;i++)
{
let value=this.shift();
//之前的缓存
if(i<start)
{
startArr.push(value)
}
//这是需要移除的部分
if(i>=start)
{
res.push(value)
}
}
// 注意从头部插入
//应用队列和栈的思想(params尾部元素出栈,入队)
while(params.length)
{
this.unshift(params.pop());
}
while(startArr.length)
{
this.unshift(startArr.pop());
}
return res;
}
测试
let arr=[1,2,3,4];
arr._splice(0,2,3,5); //[0,2]
console.log(arr); //[3,5,3,4]
//尾部替换
var a=[1,2,3,4,5,6]
console.log(a._splice(-1,1,10)) //[6]
console.log(a); //[ 1, 2, 3, 4, 5, 10 ]
Array.prototype.sort()
作用
sort() 方法用原地算法对数组的元素进行排序,并返回数组。参数为 compareFunction(比较方法),如果为空默认将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。
应用
数组排序
console.log(([2,3,2,5,3,7,5]).sort((a,b)=>a>b)) // [ 2, 2, 3, 3, 5, 5, 7 ]
console.log(([2,3,2,5,3,7,5]).sort((a,b)=>a<b)) // [ 7, 5, 5, 3, 3, 2, 2 ]
实现
思路
仅处理排序方法必传的情况
- 在数组原型上定义该方法。
- 实现一个排序算法(当前使用冒泡排序)
- 会改变原数组,需要再原数组上排序。
代码实现
Array.prototype._sort=function(compareFunction){
if(typeof compareFunction!='function')
{
throw new TypeError('compareFunction is not a function')
}
bubbleSort(this,compareFunction);
return this
/**
*
* @param {*} arr 排序数组
* @param {*} fn 比较的方法
*/
function bubbleSort(arr,fn){
for(let i=0;i<arr.length;i++)
{
let swap=false;
for(let j=0;j<arr.length-i;j++)
{
if(fn(arr[j],arr[j+1]))
{
swap=true;
let value=arr[j];
arr[j]=arr[j+1];
arr[j+1]=value;
}
}
if(!swap)
{
return arr;
}
}
}
}
测试
console.log(([2,3,2,5,3,7,5])._sort((a,b)=>a<b)) //[ 7, 5, 5, 3, 3, 2, 2 ]
结束
至此我们总结了20多个数组中常用的方法,其实还有许多API,可以参看MDN上的介绍 去熟悉使用,下面做一个简单的总结。
- 会改变原数组的API
push,pop,unshift,shift,splice,sort,reverse,七个方法,看起来很熟悉,vue2中需要对数组响应式处理需要重写的就是这七个方法。 - 返回新数组的
concat,filter,flat,map,slice等。 - 用于判断的
every,indexOf,includes,some等。 - 用于查找的
find,filter等。
数组中常用的方法和它原理实现已经基本总结完毕,总结的方法中有些未作严格的参数校验。如有错误,请谅解,欢迎批评指正。