JS数组方法总结
ES5
改变原数组
push(val)
将val添加到数组的最好,返回被修改的数组长度
let arr = [1,2,3,4]
let res = arr.push(1,2)
console.log(res,arr) //6 [1,2,3,4,1,2]
模拟实现
往数组长度的位置添加元素
Array.prototype.myPush = function(){
for(let i = 0; i < arguments.length; i++){
this[this.length] = arguments[i]
}
return this.length;
}
pop
不接收参数,删除数组中最后一个元素,返回被删除元素
let arr = [1,2,3,4]
let res = arr.pop() //一次操作只能删除一个
console.log(res,arr) // 4,[1,2,3]
模拟实现
使用length减少数组长度即可
Array.prototype.myPop = function(){
if(this.length == 0) return;
let last = this[this.length-1];
this.length--;
return last;
}
unshift(val)
添加val到数组开头,返回被修改的数组长度。
let arr = [1,2,3,4]
let res = arr.unshift(1,2) //批量添加
console.log(res,arr) // 6,[1,2,1,2,3,4]
模拟实现
把arguments与数组的数据都放到一个新数组里面,然后再覆写到原数组
Array.prototype.myUnshift = function(){
let newArr = [...arguments,...this];
let len = newArr.length
for(let i = 0; i < len; i++){
this[i] = newArr[i]
}
return this.length;
}
shift
删除数组的第一个元素,返回被删除元素
let arr = [1,2,3,4]
let res = arr.shift() //一次操作只能删除一个
console.log(res,arr) // 1,[2,3,4]
模拟实现
使用值覆盖的原理
Array.prototype.myShift = function(){
let first = this[0];
for(let i = 1; i < this.length; i++){
this[i-1] = this[i]
}
this.length? this.length-- : 'undefined'
return first;
}
reverse
反转数组,返回反转后的数组
let arr = [1,2,3,4]
let res = arr.reverse();
console.log(res,arr) //[4,3,2,1] [1,2,3,4]
---无法进行深反转---
arr = [1,[2,3],[4,5]];
res = arr.reverse();
console.log(res,arr); //[[4,5],[2,3],1] , [1,[2,3],[4,5]];
模拟实现
首尾互换。
Array.prototype.myReverse = function(){
var count = Math.floor(this.length/2);
for(let i = 0; i< this.length; i++){
if(i >= count) return this;
let temp = this[i];
this[i] = this[this.length-1-i];
this[this.length -1- i] = temp
}
}
splice(index,count,val)
从索引为index处删除count个元素,插入value,返回被删除的数据组成的新数组
let arr = [1,2,3,4];
let res = arr.splice(1,2,5)
console.log(res,arr) //[2,3] [1,5,4]
---其他操作,负数(= length+负数),count不存在默认为数组的长度---
arr = [1,2,3,4];
res = arr.splice(-2);
console.log(res,arr); //[3,4] [1,2]
---插入操作---
arr = [1,2,3,4];
res = arr.splice(-2,1,'A','B')
console.log(res,arr); [3] [1,2,'A','B',4]
模拟实现
Array.prototype.mySplice = function(index,count,...addElm){
let len = this.length;
let addCount = addElm.length;
//1. 处理参数边缘化情况
index = computedIndex(index,len);
count = computedCount(index,count,len)
console.log(index,count)
// 2. 获取删除元素,暂时放入一个新数组中
let delArr = new Array(count).fill(null);//创建长度为count,内容为null的新数组
sliceDelElm.call(this,index,count,delArr);
console.log(delArr)
console.log(addElm)
//3. 移动原数组
removeArr.call(this,count,addCount);
//4. 添加新元素到原数组中
for(let i = 0; i < addCount; i++){
this[index+i] = addElm[i]
}
this.length = this.length - count+ addCount;
return delArr;
// 初始化下标小于0或者大于数组长度
function computedIndex(index,len){
//index小于0的情况
if(index < 0) return index + len > 0 ? index + len : 0;
//index超出数组长度的边界情况
return index - len > 0 ? len : index;
}
// 没写第二个参数的或删除数量小于0或删除数量比能删的数量多的情况
function computedCount(index,count,len){
// 没写count的情况
if(typeof count == 'undefined') return len - index
// count小于0,不操作
if(count < 0) return 0;
//count > 要删除的总数
if(count > len - index) return len - index;
return count;
}
//将需删除元素放入delArr中
function sliceDelElm(index,count,delArr){
for(let i = 0; i <count; i++ ){
delArr[i] = this[index+i];
}
}
//删除原数组,三种情况,删除数量大于/小于/等于/添加数量
function removeArr(count,addCount){
//1. 删除数量 < 添加数量;说明数组长度变长了
if(count < addCount){
//向右移动的位数:addCount - count
//向右移动的元素个数(循环次数):length - (index+count)
for(let i = this.length-1; i >= index + count; i--){
let fromIndex = i;
let toIndex = i + addCount - count;
this[toIndex] = this[fromIndex];
}
}
//2. 删除数量 > 添加数量;说明数组长度变短了
else if(count > addCount){
//向前移动位数:count - addCount
//向前移动的元素个数(循环次数):length - (index+count)
for (let i = index + count; i < this.length; i++) {
let fromIndex = i;//3
let toIndex = i - count + addCount;//2
this[toIndex] = this[fromIndex];
}
//删除冗余元素,删除的次数取决于 count - addCount
for(let i = this.length - 1; i >= this.length - count + addCount; i-- ){
delete this[i]
}
}
//3. 删除数量等于增加数量 ,数组长度不变
else{
return;
}
}
}
sort (fn)
该方法默认按照数组元素ASCII 字符顺序排列,返回对原数组的引用。请注意,数组在原数组上进行排序,不生成副本。
let arr = [1,5,4,2,3,6];
let res = arr.sort();
console.log(res,arr)//(6) [1, 2, 3, 4, 5, 6] (6) [1, 2, 3, 4, 5, 6]
模拟实现
Array.prototype.mySort = function(fn){
}
不改变原数组
slice(index,len)
拷贝数组元素,拷贝区间为前闭后开[start,end)
let arr = [1,2,3,4];
let res = arr.slice(1,3);
console.log(res,arr) //[2,3] [1,2,3,4]
//不允许反向截取,允许截取的位置为负数(= length+负数),利用slice可以实现数组浅拷贝
console.log(arr.slice(1)); //[2,4,7]
console.log(arr.slice(-1)); //[7] //4+(-1)=3,start为3
console.log(arr.slice(-1,1)) //[] //4+(-1)=3,start为3,end为1,不允许反向
console.log(arr.slice(1,-1)) //[2,4]
console.log(arr.slice(-1,-2)); //[] //start为3,end为2,不允许反向截取
console.log(arr.slice(-2,-1)); //[4] //start为2,end为3
模拟实现
Array.prototype.mySlice = function(inStart,exEnd){
if(inStart == 'undefined' || exEnd == 'undefined') return;
let len = this.length;
// 处理参数边缘化情况
inStart = computedInStart(inStart,len);
exEnd = computedExEnd(inStart,exEnd,len);
let newArr = [];
for(let i = inStart; i < exEnd; i++){
newArr[newArr.length] = this[i]
}
return newArr;
// 小于0情况,大于数组长度情况
function computedInStart(inStart,len){
if(inStart < 0){
return inStart + len > 0 ? inStart + len : 0;
}
return inStart > len ? len : inStart;
}
//处理无参情况,小于0情况,大于数组长度情况
function computedExEnd(inStart,exEnd,len){
//未赋值,则为数组长度
if(typeof exEnd == 'undefined') return len;
//值小于0,
if(exEnd < 0) return exEnd + len > 0 ? exEnd + len : 0;
//值大于剩余数组长度
if(exEnd > len - inStart) return exEnd%len;
return exEnd;
}
}
concat(arr)
连接合并多个数组,返回新数组
let arr = [1,2,3,4];
let arr1 = [5,6,7,8];
let res = arr.concat(arr1);
console.log(res,arr) //[1,2,3,4,5,6,7,8] [1,2,3,4]
---支持同时合并多个数组---
let arr2 = [9,10];
let res = arr.result(arr1,arr2);
console.log(res,arr); //[1,2,3,4,5,6,7,8,9,10] [1,2,3,4]
--- concat不支持深度合并----
arr.concat([5,6],[[7,8],4]) // [1, 2, 3, 4, 5, 6, Array(2), 4]
模拟实现
Array.prototype.myConcat = function(){
let result = JSON.parse(JSON.stringify(this)); //拷贝一份数组
for(let i = 0; i < arguments.length; i++){
let argu = arguments[i];
if(Object.prototype.toString.call(argu) === '[object Array]'){
for(let j = 0; j < argu.length; j++){
result.push(argu[j])
}
}else{
result.push(argu);
}
}
return result
}
join(val)
将数组用value连接为字符串,返回连接的字符串
let arr = [1,2,3,4];
let res = arr.myJoin('.');
console.log(res,arr) //1.2.3.4 [1,2,3,4]
模拟实现
Array.prototype.join = function(char){
let result = this[0] || '';
let length = this.length;
for(let i = 1; i < length; i++){
result += char + this[i];
}
return result;
}
split()
数组迭代方法(不改变原数组)
先声明两个数据,后面的操作都以这两个数据为基础
let arr = [
{
name: '张三丰',
age: '18',
sex: 'male',
},
{
name: '张三',
age: '34',
sex: 'male'
},
{
name: '爱丽丝',
age: '16',
sex: 'female'
}
]
let obj = {name:'HSM'}
forEach
该方法接收两个参数,第一个参数是一个函数,然后反复的调用该函数,调用的次数取决了数组的长度,并且会给调用的函数传递三个参数,ele,index,self(数组本身)。第二个参数是一个对象,表示将第一个参数(函数)的this指向指向该obj,否则就是默认指向window
function deal(item,index,self){
console.log(item,index,self,this)
}
arr.myForEach(deal,obj)
模拟实现
Array.prototype.myForEach = function(func){
let len = this.length;
let _this = arguments[1] || window;
for(let i = 0; i < len; i++){
func.apply(_this,[this[i],i,this])
}
}
下面所有的方法都是基于forEach方法进行二次改进的
filter
过滤
filter方法基于forEach。
二次改进的地方在于调用该方法最终会返回一个新数组,return true的函数内容(item)会被放入到新数组中,起到过滤的作用。
function filterDeal(item,index,self){
console.log(this)
if(item.sex =='male') return true
}
var newArr = arr.filter(filterDeal,obj);
console.log(newArr)
模拟实现
Array.prototype.myFilter = function(func,obj){
let _arr = []; //add
let len = this.length;
let _this = obj || window
for(let i = 0; i < len; i++){
func.apply(_this,[this[i],i,this]) && _arr.push(this[i])//add
}
return _arr; //add
}
map(引用类型会改变原数据)
映射。
返回一个新数组,数组中的元素为原始数组元素调用函数处理后返回 的值。
当数组中元素是值类型,map不会改变原数组;当是引用类型,则可以改变原数组。因为基本类型返回的是值到新数组中,引用类型改变了内部的值
例子:引用类型值会被修改
function MapDeal(item,index,self){
console.log(this)
item.age = +item.age + 10;
return item
}
var newArr = arr.map(MapDeal,obj);
console.log(newArr)
console.log(arr)
基本类型原数组不会被修改
var arr2 = [1,2,3]
var newArr = arr2.map(function(item,index,self){
return item*2
})
console.log(newArr); //[2,4,6]
console.log(arr2); //[1,2,3]
也可以单独抽离出需要返回的内容
function MapDeal3(item,index,self){
console.log(this)
return item.age
}
var newArr = arr.map(MapDeal3,obj);
console.log('newArr:',newArr)
console.log('arr:',arr)
模拟实现
Array.prototype.myMap = function(func,obj){
let arr = [];
let len = this.length;
let _this = arguments[i] || window;
for(let i = 0; i < len; i++){
arr.push(func.apply(_this,[this[i],i,this])) //新增
}
return arr;
}
some
可以理解为promise中的race,该函数只返回一个Boolean值
判断数组中的元素是否都符合条件,有一个符合条件就返回true,全不符合条件才返回false
arr.some(function(item,index,self){
console.log(this)
if(item.age > 20){
return true
}
return false;
})
模拟实现
Array.prototype.mySome = function (func, obj) {
let flag = false;
let len = this.length;
let _this = arguments[1] || window;
for (let i = 0; i < len; i++) {
if (func.apply(_this, [this[i], i, this]) == true) {
flag = true;
break;
}
}
return flag
}
every
可以理解为Promise中的all ,该函数只返回一个Boolean值。
判断数组中的元素是否都符合条件,全符合返回true,有一个不符合就返回false
arr.every(function(item,index,self){
console.log(this)
if(item.age > 20){
return true
}
return false;
})
模拟实现
Array.prototype.myEvery = function (func, obj) {
let flag = true;
let len = this.length;
let _this = arguments[1] || window;
for (let i = 0; i < len; i++) {
if (func.apply(_this, [this[i], i, this]) == false) {
flag = false;
break;
}
}
return flag
}
reduce
从左向右进行遍历,这个方法有点像接力
原始的该方法只接收两个参数,一个是函数,一个是初始值,该函数也接收4个参数,prevValue,item,index,self,其中的prevValue默认就是initValue的值,函数每一次return的值,都会赋予prevValue,如果函数没有return ,就默认undefined,最后一次的return 会返回给外部函数接收
function reduceDeal(prev,item,index,self){
console.log(prev,item.index,self)
}
arr.reduce(reduceDeal,3)
案例:将cookie字符串形式转化成对象形式;
var str = "PSTM=1547202501;BIDUPSID=51A74B310E1C99BD28A9FA40AB749FD6;MSA_WH=375_667;BAIDUID=0D8F8152E381149:FG=1;BD_UPN=12314753;H_WISE_SIDS=140797_142277_110085;BDORZ=B490B5EBF6F3CD402E515D22BCDA1598;BD_HOME=1;H_PS_PSSID=31782_31464_31322_30824;delPer=0;BD_CK_SAM=1;PSINO=7;H_PS_645EC=bHv5XGOaNHro5ko"
function parseCookidStr(str){
var obj1 = {};
var cookieArr = str.split(/[:;]/);
return cookieArr.reduce(function(prev,cur,index,self){
var newArr = cur.split('=')
prev[newArr[0]] = newArr[1];
return prev
},obj1)
}
var cookieObj = parseCookidStr(str);
console.log('最终结果是:'cookieObj)
模拟实现
Array.prototype.myReduce = function(func,initialValue){
let len = this.length;
let _this = arguments[2] || window;
let nextValue = initialValue
for(let i = 0; i < len; i++){
nextValue = func.apply(_this,[nextValue,this[i],i,this])
}
return nextValue
}
reduceRight(func,initValue)
从右向左进行遍历
var str = "PSTM=1547202501;BIDUPSID=51A74B310E1C99BD28A9FA40AB749FD6;MSA_WH=375_667;BAIDUID=0D8F8152E381149:FG=1;BD_UPN=12314753;H_WISE_SIDS=140797_142277_110085;BDORZ=B490B5EBF6F3CD402E515D22BCDA1598;BD_HOME=1;H_PS_PSSID=31782_31464_31322_30824;delPer=0;BD_CK_SAM=1;PSINO=7;H_PS_645EC=bHv5XGOaNHro5ko"
function parseCookidStr(str){
var obj1 = {};
var cookieArr = str.split(/[:;]/);
return cookieArr.reduceRight(function(prev,cur,index,self){
console.log(prev,cur)
var newArr = cur.split('=')
prev[newArr[0]] = newArr[1];
return prev
},obj1)
}
var cookieObj = parseCookidStr(str);
console.log('最终结果是:',cookieObj)
模拟实现
Array.prototype.myReduceRight = function(func,initialValue){
let len = this.length;
let _this = arguments[2] || window;
let nextValue = initialValue
for(let i = len-1; i >= 0; i--){
nextValue = func.apply(_this,[nextValue,this[i],i,this])
}
return nextValue
}