forEach,map,filter,some,reduce五个方法都是不改变原数组的方法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>实现数组原型方法</title>
</head>
<body>
<script>
//实现forEach方法。forEach方法对数组中的每个元素执行一次给定的函数,不会直接改变调用它的对象,但是回调函数可能会改变它
Array.prototype.forEach2=function(callBack,thisArg){
if (this === null) {
throw new TypeError("this is null or not defined")
}
//typeof 可以区分基本数据类型number,string,undefined,boolean,bigint,Symbol,function,object
if (typeof callBack !== "function"){
throw new TypeError(callBack+" is not a function")
}
let o=Object(this)
//无符号位移操作符在位移前做了两种转换,第一将不是number类型的数据转换为number,第二将number转换为无符号的32位数据,也就是Unit32类型。
//x >>> 0本质上就是保证x有意义(为数字类型),且为正整数,在有效的数组范围内(0 ~ 0xFFFFFFFF),且在无意义的情况下缺省值为0
let len=o.length>>>0;
let k=0;
while (k<len){
if (k in o){
callBack.call(thisArg,o[k],k,o)
}
k++;
}
}
//实现map方法。map方法创建一个新数组,结果是该数组中每个元素调用一次函数后的返回值
let arr=[1,2,3]
Array.prototype.map2 = function (callback,thisArg) {
if (this === null){
throw new TypeError('this is null or not defined')
}
if (typeof callback !== "function"){
throw new TypeError(`${callback} is not a function`)
}
let o = Object(this)
let len = o.length>>>0;
let k=0;
let narr=[];
while (k<len){
if (k in o){
narr[k]=callback.call(thisArg,o[k],k,o)
}
k++;
}
return narr;
}
let mapArr=arr.map(x=>x*2)
console.log(mapArr)
console.log(arr.map2(x=>x*2))
//filter方法的实现。filter方法创建一个新数组,包含数组中所有通过所提供函数的元素
Array.prototype.filter2 = function (callback,thisArg) {
if (this === null){
throw new TypeError('this is null or not defined')
}
if (typeof callback !== "function"){
throw new TypeError(`${callback} is not a function`)
}
let o=Object(this)
let len=o.length>>>0
let k=0, res = [];
while (k<len){
if (k in o){
if (callback.call(thisArg,o[k],k,o)){
res.push(o[k])
}
}
k++;
}
return res;
}
let arr2=[1,1,2,2,3,1,5]
let arrf = arr2.filter2(x=>x>2)
let arrff=arr2.filter(x=>x>2)
console.log(arrf)
console.log(arrff)
//实现数组的some方法。some方法测试数组中是不是至少有一个元素通过了提供的函数的测试。返回boolean类型,空数组测试返回false
Array.prototype.some2 = function (callback,thisArg) {
if (this === null){
throw new TypeError('this is null or not defined');
}
if (typeof callback !== "function"){
throw new TypeError(`${callback} is not a function`)
}
let o =Object(this)
let len = o.length>>>0
let k=0;
while (k<len){
if (callback.call(thisArg,o[k],k,o)){
return true;
}
k++;
}
return false
}
console.log(arr2.some2(x => x>10));
//实现数组的reduce方法。reduce方法对数组中的每个元素执行给定的reducer函数,将其结果汇总为单个返回值
Array.prototype.reduce2 = function (callback,initialValue) {
if (this === null){
throw new TypeError('this is null or not defined')
}
if (typeof callback!=="function"){
throw new TypeError(`${callback} is not a function`)
}
let o =Object(this)
let len = o.length>>>0
let k=0, res;
if (arguments.length>1){
res=initialValue
}else {
//没传入初始值的时候,取数组中第一个非empty的值为初始值
while (k<len && !(k in o)){
k++;
}
if (k>len){
throw new TypeError('Reduce of empty array with no initial value')
}
res=o[k++];
}
while (k<len){
if (k in o){
res=callback(res,o[k],k,o)
}
k++;
}
return res;
}
console.log(arr.reduce2(function (acc,currentV) {
return acc+currentV;
}));
console.log(arr.reduce(function (acc,currentV) {
return acc+currentV;
}));
</script>
</body>
</html>
总结,虽然这些原型方法已经内置,不需要自己实现,但是手写这些方法的意义可能在于更加了解这些方法。
1. forEach方法对数组中每个元素执行回调函数,该方法不会直接改变原数组,但是原数组是否会被改变取决于回调函数是否改变原数组
2. map方法对数组中每个元素执行会回调函数,返回由每个元素执行回调函数的结果组成的新数组(不改变原数组)。
3. filter方法对数组中的每个元素执行回调函数,返回 由 数组中 通过了回调函数(即 使得回调函数返回true)的 元素组成的数组,不改变原数组
4. some方法对数组中的元素执行回调函数,返回布尔值,表示数组中是否存在元素 通过了回调函数(即 使得回调函数返回true),不改变原数组
5. reduce方法 MDN中是这么说的 “对数组中每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值” 。我不太理解,不改变原数组
其他,
1. typeof 可以区分基本数据类型number,string,undefined,boolean,bigint,Symbol,function,object
2. 无符号位移操作符在位移前做了两种转换,第一将不是number类型的数据转换为number,第二将number转换为无符号的32位数据,也就是Unit32类型。
x >>> 0本质上就是保证x有意义(为数字类型),且为正整数,在有效的数组范围内(0 ~ 0xFFFFFFFF),且在无意义的情况下缺省值为0