文章目录
前言
面试中经常会问到,比如让手写一个push方法等等,这期就写一些数组常用的方法
一、手写push方法
Array.prototype.push = Array.prototype.push || function() {
for(var i = 0; i < arguments.length; i++) {
// 将传递的参数每次都追加到数组的最后面
this[this.length] = arguments[i]
}
// 返回数组长度
return this.length;
}
二、手写pop方法
Array.prototype.pop = Array.prototype.pop || function() {
// 如果数组为空,直接return;
if(this.length === 0) return;
// 先保存最后一个元素
var lastItem = this[this.length - 1];
// 通过设置数组的length属性来实现删除元素的效果
this.length = this.length - 1;
return lastItem;
}
三、手写unshift方法
Array.prototype.unshift = Array.prototype.unshift || function() {
var argLen = arguments.length; // 获取实参列表的长度并保存
var len = this.length + argLen; // unift完以后数组的长度 = 原数组的长度+实参列表的长度
// 在这里采用倒着循环,目的是空出原数组的位置,然后将原数组中的元素后移
for(var i = len - 1; i >= 0; i--) {
this[i] = this[i - argLen] // 将原数组元素后移
// 举例说明:假设原数组为[1, 2], 要插入的元素为a, b。经此操作原数组变成:[undefined, undefined, 1, 2]
}
// 循环实参列表,将实参列表中的元素依次填入原数组的空白位置
for(var i = 0; i < argLen; i++) {
this[i] = arguments[i]
}
// 返回数组长度
return len;
}
四、手写shift方法
Array.prototype.shift = Array.prototype.shift || function() {
var res = this[0]; // 保存数组的第0项的值
var len = this.length; // 获取并保存数组的长度
for(var i = 0; i < len; i++) {
if(i >= len - 1) { // 当下标是数组的长度-1时,直接退出循环。因为最后一项没必要赋值
break;
} else {
// 将数组的后一项赋值给前一项
this[i] = this[i + 1];
}
}
// 删除数组的最后一项
this.length = len - 1;
return res; // 返回数组的第0项
}
五、手写splice方法
Array.prototype.splice = Array.prototype.splice || function() {
// 没有传递参数的时候,直接返回一个空数组
if(arguments.length === 0) return [];
var startIndex = arguments[0]; // 起始下标
var delArr = []; // 删除的元素
// 传递一个参数的时候
if(arguments.length === 1) {
if(startIndex >= 0) { // 起始下标是正数的情况
// 保存删除的元素
for(var i = startIndex; i < this.length; i++) {
delArr[i - startIndex] = this[i];
}
this.length = startIndex;
} else { // 如果起始下标是负数的话,应该是从后面开始
for(var i = 0; i < Math.abs(startIndex); i++) {
delArr[i] = this[this.length + startIndex + i]
}
// 删除对应的元素
this.length = this.length + startIndex;
}
}
// 当传递两个以上参数的时候
if(arguments.length >= 2) {
var num = arguments[1]; // 替换的元素个数
var argLen = arguments.length - 2; // 待替换的元素的个数
// 如果splice的第二个参数是负数,则返回空数组,不做任何处理
if(num < 0) return [];
for(var i = startIndex; i < startIndex + num; i++) {
// 先保存代替换的元素
delArr[i - startIndex] = this[i];
// 替换对应的元素
this[i] = arguments[i - startIndex + 2];
}
// 处理待替换元素个数大于替换元素个数的情况
if(argLen > num) {
// 提前保存可能会被替换的元素但是不应该被替换的元素。
// 例如:['a', 'b', 'c', 'd'],假设被替换的元素应该是a,b,但是实际传递了1, 2, 3 这三个元素。那么c, d就不应该被替换
var saveArr = [];
// 计算可能会被替换的元素的个数
var count = this.length - num - startIndex;
// 保存会被替换的元素的个数
for(var i = 0; i < count; i++) {
saveArr[i] = this[this.length - count + i];
}
// console.log(saveArr)
// 将数组中对应的元素个数进行替换
for(var i = startIndex; i < startIndex + argLen; i++) {
// 替换对应的元素
this[i] = arguments[i - startIndex + 2];
}
for(var i = 0; i < saveArr.length; i++) {
this[this.length] = saveArr[i];
}
}
// 处理待替换的元素个数小于替换的元素个数的情况
if(argLen < num) {
for(var i = 0; i < num - argLen; i++) {
// 循环数组中的元素
for(var j = 0; j < this.length; j++) {
// 将不是undefined的元素前置,是undefined的元素后置
this[j] == undefined && (this[j] = this[j + 1]);
}
}
// 删除是undefined的元素
this.length = this.length - (num - argLen);
}
}
return delArr;
}
六、手写indexOf方法
Array.prototype.indexOf = Array.prototype.indexOf || function(el, startIndex) {
// 设置参数的默认值
startIndex = startIndex || 0;
var index = -1;
if(startIndex >= 0) {
for(var i = startIndex; i < this.length; i++) {
this[i] === el && (index = i);
}
}
return index;
}
七、手写concat方法
Array.prototype.concat = Array.prototype.concat || function() {
// 声明一个新数组
var arr = [];
// 将原数组的值拷贝到新数组
for(var i = 0; i < this.length; i++) {
arr[i] = this[i];
}
if(arguments.length > 0) {
// 将传递的新数组依次拷贝到 arr 中
for(var i = 0; i < arguments.length; i++) {
// 判断传入的参数是否是一个数组
if(Object.prototype.toString.call(arguments[i]) === '[object Array]') {
for(var j = 0; j < arguments[i].length; j++) {
arr[arr.length] = arguments[i][j]
}
} else {
arr[arr.length] = arguments[i];
}
}
}
// 返回 arr 这个新数组
return arr;
}
八、手写reverse方法
Array.prototype.reverse = function() {
var result = []; // 声明一个新数组
// 将原数组倒序放入新数组
for(var i = this.length - 1; i >= 0; i--) {
result[result.length] = this[i];
}
// 修改原数组中的值
for(var i = 0; i < result.length; i++) {
this[i] = result[i];
}
return result;
}
九、手写forEach方法
Array.prototype.forEach = Array.prototype.forEach || function(fn) {
// this指向调用forEach方法的数组实例
for(var i = 0; i < this.length; i++) {
fn(this[i], i, this)
}
}
十、手写map方法
Array.prototype.map = Array.prototype.map || function(fn) {
// 声明一个新数组
var arr = []
for(var i = 0; i < this.length; i++) {
// fn 函数的执行结果即为调用map方法时传递的函数的返回值(即判断条件)
arr.push(fn(this[i], i, this))
}
return arr;
}
十一、手写filter方法
Array.prototype.filter = Array.prototype.filter || function(fn) {
var arr = [];
for(var i = 0; i < this.length; i++) {
// fn 的执行结果即为调用filter方法时传递的函数的返回值(即为过滤条件)
fn(this[i], i, this) && arr.push(this[i])
}
return arr;
}
十二、手写every方法
Array.prototype.every = Array.prototype.every || function(fn) {
var flag = true;
for(var i = 0; i < this.length; i++) {
// 思路:检查数组中的元素是否都满足条件,只要有一个不满足条件就将 flag 设置为false同时退出循环
if(!fn(this[i], i, this)) {
flag = false;
break;
}
}
// 返回flag,flag的最终结果即为every方法的最终执行结果
return flag;
}
十三、手写some方法
Array.prototype.some = Array.prototype.some || function(fn) {
var flag = false;
for(var i = 0; i < this.length; i++) {
if(fn(this[i], i, this)) {
flag = true;
break;
}
}
return flag;
}
十四、手写reduce方法
Array.prototype.reduce = Array.prototype.reduce || function(fn, initialValue) {
// 判断初始化的值是否存在,如果存在下标从0开始,不存在下标从1开始
var startIndex = initialValue ? 0 : 1;
// 如果初始化的值存在,回调函数的第一个参数为初始化的值,不存在初始化的值为数组的第一项
var type = initialValue ? initialValue : this[0];
for(var i = startIndex; i < this.length; i++) {
// 将返回值赋给回调函数的第一个参数
type = fn(type, this[i], i, this)
}
return type;
}
十五、手写findIndex方法
Array.prototype.findIndex = function(fn) {
var index = -1;
for(var i = 0; i < this.length; i++) {
// 如果满足条件
if(fn(this[i], i, this)) {
// 将 i 赋值给 index
index = i;
// 退出循环
break;
};
}
return index;
}
十六、手写flat方法
// 参数deep: 代表递归的层级
Array.prototype.flat = Array.prototype.flat || function(deep) {
// 给deep设置默认值,如果传递deep择取传递的deep,如果没有传递则默认是1
deep = deep == undefined ? 1 : deep;
var arr = [];
for(var i = 0; i < this.length; i++) {
// 判断数组中的元素是否是一个数组并且 deep 是否大于0
if(Object.prototype.toString.call(this[i]) === '[object Array]' && deep > 0) {
arr = arr.concat(this[i].flat(deep - 1))
} else {
// 如果不是数组则将其添加到 arr 中
arr.push(this[i])
}
}
return arr;
}
总结
喜欢的话可以关注一下博主