手写实现数组部分方法一

前言

前端工作中进行前后端联调数据,我们常常拿到的是后端返回给我们 json 数据,然而进行渲染的注意数据还是存放在数组当中,这时拿到的数据常常也不是我们想要格式而是进行一系列的整合,而实现整合就离不开数组常用方法

最近把数组的常用方法都手写了一遍,整理到了一块儿,顺便就分享出来,如有不合理之处请评论处指出

push

push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度,改变原数组

/**
 * push 方法可应用在类似数组的对象上
 * 接收参数个数无限制,可以是字符串、数值或引用类型,返回原数组的长度
 * 遍历参数,每遍历一个参数,原数组长度加 1,并把这个参数赋给这个新的索引,最后返回原数组长度
 */
Array.prototype.push = function(...args) {
  let O = Object(this);  // ecma 中提到的先转换为对象(使用包装类进行包装),因为 push 可应用在类似数组的对象上
  // 如果想之应用数组上,上面那行可以省略直接保存 this 
  let len = this.length >>> 0;  // 使用位运算进行将传入不合法数据转化为整数
  let argCount = args.length >>> 0;
  // 遍历参数
  for(let i = 0; i < argCount; i++) {
    O[len + i] = items[i];
  }
  let newLength = len + argCount;  // 添加后的总数组长度
  O.length = newLength;
  return newLength;
}

// 测试代码
var arr = [1, 2, 3, 4];
console.log(arr.push(5, 6, 7, 8));   // 8 
console.log(arr);  // [1, 2, 3, 4, 5, 6, 7, 8]

pop

pop()方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度,所以改变原数组

/**
 * pop 方法具有通用性,可应用在类似数组的对象上
 * 不接受参数,删除原数组最后一项,当数组为空时返回 undefined
 * 原数组长度减 1,返回被删除的项
 */ 
Array.prototype.pop = function() {
  let O = Object(this);  // 获取 this 指向
  let len = this.length >>> 0;
  // 空数组情况
  if (len === 0) {
    O.length = 0;
    return undefined;
  }
  len --;
  let value = O[len];
  delete O[len];
  O.length = len;
  return value;
}

// 测试代码
var arr = [1, 2, 3, 4];
console.log(arr.pop());  // 4
console.log(arr);  // [ 1, 2, 3 ]

unshift

unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)

/** 
 * unshift 方法可以作用于类数组对象上
 * 接收不限个数的参数 
 * 返回原数组长度
 * 先将把原数组所有项后移一位,然后遍历参数在数组头部添加该参数
 */
Array.prototype.unshift = function (...args) {
    let O = Object(this);
    let len = this.length >>> 0;
    let argCount = args.length >>> 0;
    // 当空数组时
    if (len === 0) {
        for (let i = 0; i < argCount; i++) {
            O[i] = args[i];
        }
        return argCount;
    }
    // 把原数组往后移动
    for (let i = argCount + len - 1; i > argCount - 1; i--) {
        O[i] = O[i - len];
    }
    // 将形参数据遍历放数组前
    for (let i = 0; i < argCount; i++) {
        O[i] = args[i];
    }
    return O.length;
}

// 测试代码
var arr = [];
console.log(arr.unshift(1, 2, 3, 4));  // 4
console.log(arr); // [ 1, 2, 3, 4 ]

shift

shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度,原数组改变

/** 
 * shift 方法不局限于数组,作用于类似数组的对象上
 * 不接受参数,如果数组为空则返回 undefined
 * 把原数组中所有的项向前移一位,原数组长度减一
 */   
Array.prototype.shift = function () {
   let O = Object(this);
   let len = this.length >>> 0;
   // 空数组情况
  if (len === 0) {
    O.length = 0;
    return undefined;
  }
   let result = O[0];
   for (let i = 0; i < len - 1 ; i++) {
    	O[i] = O[i + 1]
   }
   len --;
   O.length = len;
   return result
}

// 测试
var arr = [];
console.log(arr.shift());  // undefined
console.log(arr);  // []
var arr = [1, 2, 3, 4];
console.log(arr._shift());  // 1
console.log(arr); // [2,3,4]

forEach

forEach() 方法对数组的每个元素执行一次给定的函数

/** 
 * forEach 方法
 *  接收一个函数参数和一个函数执行作用域的参数(可选)
 *  回调函数参数函数也接受3个参数,分别是数组当前项的值,当前数组当前项的索引(可选),当前数组对象本身(可选)
 *  执行参数函数,默认执行环境为window,不返回任何值
 */
Array.prototype.forEach = function (fn) {
	let O = Object(this);
    let len = this.length >>> 0;
    // 处理做些兼容 node 环境处理(回调函数this指向)
    let _this = arguments[1] || (typeof window === "undefined" ? {} : window);
    // 传入的不是回调函数
    if (typeof fn !== "function") {
      throw new TypeError(fn + ' is not a function');
    }
	// 遍历传入回调函数
    for (let i = 0; i < len; i++) {
   		// 改变 this 指向
        fn.apply(_this, [O[i], i, O])
    }
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
arr.forEach((item, index, self) => {
    console.log(item, index, self, this)
}, obj)

// 1 0 [ 1, 2, 3, 4, 5 ] 
// 2 1 [ 1, 2, 3, 4, 5 ]
// 3 2 [ 1, 2, 3, 4, 5 ] 
// 4 3 [ 1, 2, 3, 4, 5 ] 
// 5 4 [ 1, 2, 3, 4, 5 ]

map

map() 方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成

/** 
 * map 方法
 * 接收一个函数参数和一个函数执行作用域的参数(可选)
 * 参数函数也接受3个参数,分别是数组中正在处理的当前元素,数组中正在处理的当前元素的索引(可选),当前调用的数组(可选)
 * 执行参数函数,默认执行环境为window
 */
Array.prototype.map = function (fn) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[1] || (typeof window === "undefined" ? {} : window);
    // 传入的不是回调函数
    if (typeof fn !== "function") {
      throw new TypeError(fn + ' is not a function');
    }
    let newArr = new Array(len);
    for (let i = 0; i < len; i++) {
        // 将每次返回的结果获取得到映射关系
        newArr[i] = fn.apply(_this, [O[i], i, O]);
    }
    return newArr
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.map((item, index, self) => {
    console.log(item, index, self, this);
    // 1 0 [ 1, 2, 3, 4, 5 ] 
	// 2 1 [ 1, 2, 3, 4, 5 ] 
	// 3 2 [ 1, 2, 3, 4, 5 ] 
	// 4 3 [ 1, 2, 3, 4, 5 ] 
	// 5 4 [ 1, 2, 3, 4, 5 ] 
    return item + 2;
}, obj);
console.log(newArr);  // [ 3, 4, 5, 6, 7 ]

filter

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素

/** 
 * filter 方法
 * 接收一个函数参数和一个函数执行作用域的参数(可选)
 * 参数函数也接受3个参数,分别是前正在处理的元素,正在处理的元素在数组中的索引(可选),调用了 filter 的数组本身(可选)
 * 执行参数函数,默认执行环境为window
 */ 
Array.prototype.filter = function (fn) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[1] || (typeof window === "undefined" ? {} : window);
    if (typeof fn !== "function") {
      throw new TypeError(fn + ' is not a function');
    }
    let newArr = [];
    if(len === 0) return newArr;
    for (let i = 0; i < len; i++) {
        // 根据函数返回值判断真假符合要求
        fn.apply(_this, [O[i], i, O]) && newArr.push(O[i]);
    }
    return newArr
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.filter((item, index, self) => {
    console.log(item, index, self, this);
    // 1 0 [ 1, 2, 3, 4, 5 ] 
    // 2 1 [ 1, 2, 3, 4, 5 ] 
	// 3 2 [ 1, 2, 3, 4, 5 ]
    // 4 3 [ 1, 2, 3, 4, 5 ] 
    // 5 4 [ 1, 2, 3, 4, 5 ] 
    return item > 3
}, obj)
console.log(newArr );  // [ 4, 5 ]

some

some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值

如果用一个空数组进行测试,在任何情况下它返回的都是 false

/**
 * some 方法
 * 接收一个函数参数和一个函数执行作用域的参数(可选)
 * 参数函数也接受3个参数,分别是正在处理的元素,当前正在处理的元素的索引值(可选),当前some()被调用的数组(可选)
 * 执行参数函数,默认执行环境为window
 * 数组中有至少一个元素通过回调函数的测试就会返回true;所有元素都没有通过回调函数的测试返回值才会为false
 */ 
Array.prototype.some = function (fn) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[1] || (typeof window === "undefined" ? {} : window);
    if (typeof fn !== "function") {
      	throw new TypeError(fn + ' is not a function');
    }
    if(len === 0) return false;
    for (let i = 0; i < len; i++) {
        // 遇到函数返回 true 最终就是返回 true
        if (fn.call(_this, 	O[i], i, O)) {
            return true;
        }
    }
    return false
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.some((item, index, self) => {
    console.log(item, index, self, this);
    // 1 0 [ 1, 2, 3, 4, 5 ]
	// 2 1 [ 1, 2, 3, 4, 5 ] 
	// 3 2 [ 1, 2, 3, 4, 5 ] 
    return item > 2
}, obj)
console.log(newArr ); // true

every

every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值

若收到一个空数组,此方法在一切情况下都会返回 true

/**
 * every 方法
 * 接收一个函数参数和一个函数执行作用域的参数(可选),
 * 参数函数也接受3个参数,分别是用于测试的当前值,当前用于测试的当前值的索引(可选),当前调用 every 的当前数组(可选)
 * 执行参数函数默认执行环境为window
 * 如果回调函数的每一次返回都为 true 值,返回 true ,否则返回 false
 */  
Array.prototype.every = function (fn) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[1] || (typeof window === "undefined" ? {} : window);   // 作用域 this 指向可能在 node 运行环境中
    if (typeof fn !== "function") {
      	throw new TypeError(fn + ' is not a function');
    }
    if(len === 0) return true;
    for (let i = 0; i < len; i++) {
        // 遇到函数返回 true 最终就是返回 true
        if (!fn.call(_this, O[i], i, O)) {
            return false;
        }
    }
    return true
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.every((item, index, self) => {
    console.log(item, index, self, this);
    // 1 0 [ 1, 2, 3, 4, 5 ] 
	// 2 1 [ 1, 2, 3, 4, 5 ] 
	// 3 2 [ 1, 2, 3, 4, 5 ] 
    return item < 3
})
console.log(newArr);  // false
var arr = [];
console.log(arr.every((item) => item > 6));  // true

reduce

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值

reduce() 是高阶函数,常用于计算求和操作

/* 
* reduce 方法
* 接收函数参数和一个初始值,初始值默0,
* 参数函数也有四个参数,分别是上一次调用 callbackFn 时的返回值,正在处理的元素,正在处理的元素的索引,当前用于遍历的数组
* 遍历数组,依次把当前项与上一项之和,当前项的值,当前项索引,当前数组传入参数函数
* 执行参数函数,并把归并后的值保存下来,提供给下一项使用,使用 “reducer” 回调函数遍历整个数组后的结果
*/
Array.prototype.reduce = function (fn, initialValue) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[2] || (typeof window === "undefined" ? {} : window);   // 作用域 this 的指向
    if (typeof fn !== "function") {
      	throw new TypeError(fn + ' is not a function');
    }
    let i = initialValue ? 0 : 1;
    // 是否有默认值没有则默认数组第一项
    initialValue = initialValue ? initialValue : O[0];
    for (; i < len; i++) {
        initialValue = fn.apply(_this, [initialValue, O[i], i, O]);
    }
    return initialValue
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.reduce((prev, curr, index, self) => {
    console.log(prev, curr, index, self);
    // 1 2 1 [ 1, 2, 3, 4, 5 ]
    // 3 3 2 [ 1, 2, 3, 4, 5 ]
    // 6 4 3 [ 1, 2, 3, 4, 5 ] 
    // 10 5 4 [ 1, 2, 3, 4, 5 ]
    return prev + curr
})
console.log(newArr );  // 15
var newArr = arr.reduce((prev, curr, index, self) => {
    console.log(prev, curr, index, self);
   	// 10 1 0 [ 1, 2, 3, 4, 5 ]
	// 11 2 1 [ 1, 2, 3, 4, 5 ]
	// 13 3 2 [ 1, 2, 3, 4, 5 ]
	// 16 4 3 [ 1, 2, 3, 4, 5 ]
	// 20 5 4 [ 1, 2, 3, 4, 5 ]
    return prev + curr
},10)
console.log(newArr );  // 25

reduceRight

reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值

/* 
* reduceRight 方法
* 接收函数参数和一个初始值,
* 参数函数也有四个参数,分别是上一次调用 callbackFn 时的返回值,正在处理的元素,正在处理的元素的索引,当前用于遍历的数组
* 遍历数组,依次把当前项与上一项之和,当前项的值,当前项索引,当前数组传入参数函数
*/
Array.prototype.reduceRight = function (fn, initialValue) {
    let O = Object(this);
    let len = this.length >>> 0;
    let _this = arguments[2] || (typeof window === "undefined" ? {} : window);   // 作用域 this 的指向
    if (typeof fn !== "function") {
      	throw new TypeError(fn + ' is not a function');
    }
    initialValue = null;  // 利用 null 转化为数字时为 0 ===> 此方法没有 initialValue 跟自带 reduce 相比会多循环一次
    for (let i = len - 1; i >= 0; i--) {
        initialValue = fn.apply(_this, [initialValue, O[i], i, O]);
    }
    return initialValue
}

// 测试代码
var arr = [1, 2, 3, 4, 5];
var obj = {
    a: 1,
    b: 2,
}
var newArr = arr.reduceRight((prev, curr, index, self) => {
    console.log(prev, curr, index, self);
    // null 5 4 [ 1, 2, 3, 4, 5 ]
	// 5 4 3 [ 1, 2, 3, 4, 5 ]
	// 9 3 2 [ 1, 2, 3, 4, 5 ]
	// 12 2 1 [ 1, 2, 3, 4, 5 ]
	// 14 1 0 [ 1, 2, 3, 4, 5 ]
    return prev + curr
});
console.log(newArr); // 15

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值