1、reduce 将一个数组中的一系列值计算出一个值(从左往右算)
//result 表示所有计算结束后返回的值,也就是最后一次return的值
let result = arr.reduce(function(val,item,index,origin){
//val当前值,
//item当前元素,
//index当前索引,
//origin老数组
return 表达式; //每次return的值都会成为新的val
},initval);
//initval代表初始值
//注意,如果有initval,则会将这个初始值先赋值给第一次的val;如果没有,val就是第一个元素,item就是第二个元素,也就是会少循环一次;同样,没有初始值,那么index就从1开始,而不是从0开始
举例——求和:
let arr = [1,2,3];
arr.reduce(function(val,item,index,origin){
return val + item;
},0)
举例——求平均值
let arr = [1,2,3];
arr.reduce(function(val,item,index,origin){
let sum = val + item;
if(index === origin.length - 1){
return sum/origin.length;
}else{
return sum;
}
},0)
1.1、用es5实现reduce方法【原理】
Array.prototype.reduce = function(reduceFn,initVal){
if(typeof reduceFn !== 'function'){
throw new Error(`${reduceFn} is not a function`);
return;
}
var initIndex;
if(typeof initVal === 'undefined'){
initVal = this[0];
initIndex = 1;
}else{
initIndex = 0;
}
for(var i = initIndex;i < this.length; i++){
initVal = reduceFn(initVal,this[i],i,this);
}
return initVal;
}
//举例:求和
let arr = [1,2,3];
let result;
result = arr.reduce(function(val,item,index,origin){
return val + item;
},0);
console.log(result);//6
2、reduceRight与reduce类似,唯一不同的是前者从右往左计算,后者从左往右计算。
举例——求平均数
let arr = [1,2,3];let resulet = arr.reduce(function(val,item,index,origin){
let sum = val + item;
if(index === 0){
return sum/origin.length;
}else{
return sum;
}
},0)
2.1、用es5实现reduceRight方法
Array.prototype.reduceRight = function(reduceFn,initVal){
if(typeof reduceFn !== 'function'){
throw new Error(`${reduceFn} is not a function`);
return;
}
var initIndex;
if(typeof initVal === 'undefined'){
initVal = this[this.length - 1];
initIndex = this.length - 2;
}else{
initIndex = this.length - 1;
}
for(var i = initIndex;i >= 0; i--){
initVal = reduceFn(initVal,this[i],i,this);
}
return initVal;
}
3、origin
origin指的是原数组,那么当我们存在原数组跟新数组的时候,必须要关注一个问题——两者之间是引用关系还是简单的值拷贝关系?
很简答,当我们去改变origin的值的时候,去打印原数组,如果原数组也改变,那么就说明引用关系,反之则为值拷贝关系。
let arr = [1,2,3];
let result = arr.reduceRight(function(val,item,index,origin){
origin[index] = origin[index]+'zhuangzhuang';
},0)
console.log(arr);//['1zhuangzhuang','2zhuangzhuang','3zhuangzhuang'];
上面的例子,可见是引用关系。
在回到上面看原理,其实我们并没有去处理origin,而是直接引用,所以原理中也是引用关系
filter这个方法,用于对数组的过滤
let arr = [1,2,3,4,5];
let newArr = arr.filter(function(item,index,origin){
return 布尔值;
},thisArg)
/*
filter有两个参数:
1.callback
callback有三个参数
a.item 数组中正在处理的元素
b.index 数组中正在处理的元素的索引值
c.被调用数组,即arr,这跟reduce的origin一样,是引用关系
2.thisArg
用于改变callback中的this指向
*/
//return true,把此元素保留在数组中
//return false,把此元素不保留在数组中
//newArr 范围值为新元素,该方法不修改原来的数组
举例一:
let arr = [1,2,3,4,5,6];
let newArr = arr.filter(function(item,index){
return item > 3;
})
console.log(newArr);//[4,5,6]
这样,就直接过滤出大于3的每项元素了,组成一个新数组
那么,用es5怎么来实现呢?
真的极其简单:
/*
用es5解释es6中filter的原理
*/
Array.prototype.filter = function(filterFn,thisArg){
let newArr = [];
for(var i = 0;i<_this.length;i++){
let _this = this.slice(0);//注意,务必要先复制一份
filterFn.call(thisArg,_this[i],i,this) && newArr.push(_this[i]);
}
return newArr;
}
let arr = [1,2,3,4,5,6];
let newArr = arr.filter(function(item,index,origin){
console.log(this);//'zhuangzhuang'
return item > 3;
},'zhuangzhuang')
console.log(newArr,arr);//[4,5,6]
需要注意一点:
当我们去改变origin的时候,并不能改变item,因为item是origin的副本中的项
如果thisArg不传,在非严格模式下将会是全局对象,严格模式下是 undefined。
关于filter,有专门写一篇文章,详细请查看>>传送门<<
该方法主要用于查找数组元素
let arr = [1,2,3,4];
let result = arr.find(function(item,index,origin){
return item % 2 === 0;
},'zhuangzhuang')
console.log(result);//2
可见,其实他找到的是满足return后面为true的第一个元素。一旦找到,就不再往后面查找。
原理跟filter一样简单:
/*
用es5解释es6中find的原理
*/
Array.prototype.find = function(filterFn,thisArg){
let newArr = [];
for(var i = 0;i<_this.length;i++){
let _this = this.slice(0);
if(filterFn.call(thisArg,_this[i],i,this)){
return _this[i];
}
}
}
let arr = [1,2,3,4,5,6];
let newArr = arr.find(function(item,index,origin){
return item % 2 === 0;
},'zhuangzhuang')
console.log(newArr,arr);//2 (6) [2, 3, 3, 4, 5, 6]
跟filter一样,需要注意一点:
当我们去改变origin的时候,并不能改变item,因为item是origin的副本中的项
如果thisArg不传,在非严格模式下将会是全局对象,严格模式下是 undefined。
跟上面的find一样,唯一的区别是上面的find返回元素,这个findIndex返回的是索引
let arr = [1,2,3,4];
let result = arr.findIndex(function(item,index){
return item % 2 === 0;
})
console.log(result);//1
原理:
Array.prototype.findIndex = function(filterFn,thisArg){
let newArr = [];
for(var i = 0;i<_this.length;i++){
let _this = this.slice(0);
if(filterFn.call(thisArg,_this[i],i,this)){
return i;
}
}
}
let arr = [1,2,3,4,5,6];
let newArr = arr.findIndex(function(item,index,origin){
return item % 2 === 0;
},'zhuangzhuang')
console.log(newArr,arr);
跟filter一样,需要注意一点:
当我们去改变origin的时候,并不能改变item,因为item是origin的副本中的项
如果thisArg不传,在非严格模式下将会是全局对象,严格模式下是 undefined。
与上面的不同的是,some和every返回的是布尔值
some:存在满足条件的 即返回true,否则返回false
every:所有元素都满足条件 即返回true,否则返回false
let arr = [1,2,3,4];
let bool = arr.some(function(item,index,origin){
return item > 1;
},null)
console.log(bool);//true,存在元素大于1的
let arr = [1,2,3,4];
let bool = arr.every(function(item,index,origin){
return item > 1;
},null)
console.log(bool);//false,有一个没有大于1
原理同上,非常简单,就不写了
如果thisArg不传,在非严格模式下将会是全局对象,严格模式下是 undefined。
类数组:具有length属性,但不具有数组方法的数据格式,比如DOM、arguments等,具体可以看这篇文章:>>传送门<<
那么,类数组如何转变成数组,在这里介绍两种方法:
let arr = Array.prototype.slice.call(类数组);
>arr即为数组
>在这里,如果你想让类数组遍历,使用数组forEach方法,可以直接如下:
Array.prototype.forEach.call(类数组,function(item,index,origin){
})
let arr = Array.from(类数组);
>arr即为数组
Array.of(3);//[3]
Array.of(3,4);//[3.4]
Array(3);//[empty × 3]长度为3,但是没有元素
Array(3,4);//[3,4]
new Array(3);//[empty × 3]长度为3,但是没有元素
new Array(3,4);//[3,4]
(以下正在写…)
1、浅拷贝与深拷贝的区别
2、如何实现深拷贝
方法一:转字符串再转回来
方法二:递归(要考虑object包含null、Array、function、object)