前言
今天手写几个常用的方法,实现的方式有很多,欢迎指正,如果有更好的方式可以在评论区留言
1.手写forEach方法
这个方法是在数组原型上添加一个自定义的方法,用于遍历数组并执行回调函数。回调函数的参数包括当前遍历到的元素值、元素索引和原数组对象。通过调用回调函数的call方法,可以将this指向当前数组对象。
Array.prototype.myForEach = function (callback) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
for (let i = 0, len = this.length; i < len; i++) {
callback.call(this, this[i], i, this);
}
};
const arr = ["我", "是", "大帅比"];
arr.myForEach((val, index) => {
console.log(`${index}-${val}`);
});
2.手写Filter方法
这个方法也是在数组原型上添加一个自定义的方法,用于筛选数组中符合条件的元素,并返回一个新的数组。回调函数的参数同样包括当前遍历到的元素值、元素索引和原数组对象。如果回调函数的返回值为真,则将当前元素值保存到一个结果数组中。
Array.prototype.myFilter = function (callback) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
let result = [];
for (let i = 0, len = this.length; i < len; i++) {
if (callback.call(this, this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
const animals = [
{ name: "鸡", age: 1 },
{ name: "小猪", age: 5 },
{ name: "羊咩咩", age: 3 },
];
console.log(animals.myFilter((animal) => animal.age > 2));
3.手写map方法
这个方法也是在数组原型上添加一个自定义的方法,用于对数组中的每一个元素执行回调函数,并返回一个新的数组。回调函数的参数同样包括当前遍历到的元素值、元素索引和原数组对象。将回调函数的返回值保存到结果数组中即可。
Array.prototype.myMap = function (callback) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
let result = [];
for (let i = 0, len = this.length; i < len; i++) {
result.push(callback.call(this, this[i], i, this));
}
return result;
};
const animals = [
{ name: "鸡", age: 1 },
{ name: "小猪", age: 5 },
{ name: "羊咩咩", age: 3 },
];
console.log(animals.myMap((val) => val.name));
4.手写some方法
这个方法同样是在数组原型上添加一个自定义的方法,用于判断数组中是否有元素符合条件。回调函数的参数同样包括当前遍历到的元素值、元素索引和原数组对象。如果回调函数的返回值为真,则返回true;否则继续遍历数组。如果遍历完整个数组都没有找到符合条件的元素,则返回false。
Array.prototype.mySome = function (callback) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
for (let i = 0, len = this.length; i < len; i++) {
if (callback.call(this, this[i], i, this)) return true;
}
return false;
};
const numArr = [1, 3, 5, 1, 2, 6, 121, 2, 33, 6];
console.log(numArr.mySome((val) => val > 20));
console.log(numArr.mySome((val) => val > 200));
5.手写every方法
这个方法和some方法的实现方式基本相同,只不过判断条件相反。如果回调函数对于每一个元素的返回值都为真,则返回true;否则返回false。
Array.prototype.myEvery = function (callback) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
for (let i = 0, len = this.length; i < len; i++) {
if (!callback.call(this, this[i], i, this)) return false;
}
return true;
};
const numArr = [1, 3, 5, 1, 2, 6, 121, 2, 33, 6];
console.log(numArr.myEvery((val) => val > 0));
console.log(numArr.myEvery((val) => val > 100));
6.手写reduce方法
这个方法是对数组进行累加的方法,它接收一个回调函数作为参数,这个回调函数接收四个参数,分别是累加器、当前值、当前索引和数组本身。这个方法有两种用法,一种是不传初始值,这时候累加器默认为数组的第一项,从数组第二项开始执行回调函数;另一种是传递了初始值,这时候累加器为初始值,从数组第一项开始执行回调函数。这个方法的实现思路就是遍历数组,将累加器和当前值传入回调函数,回调函数返回的结果再作为累加器,不断更新累加器的值,最后返回累加器的值。
Array.prototype.myReduce = function (callback, initialValue) {
if (typeof callback !== "function") {
throw new Error("callback must be a function");
}
let result = initialValue;
let index = 0;
if (initialValue === undefined) {
result = this[0];
index = 1;
}
for (let len = this.length; index < len; index++) {
result = callback(result, this[index], index, this);
}
return result;
};
const numArr = [2, 5, 6, 8];
console.log(
numArr.myReduce((sum, val) => {
console.log(val);
return sum + val;
})
);
console.log(
numArr.myReduce((sum, val) => {
console.log(val);
return sum + val;
}, 3)
);
7.手写bind方法
这个方法是用来改变函数执行时的this指向的,它接收一个对象作为this指向,以及一些参数。这个方法的实现思路就是在调用bind方法的函数中保存原函数的引用,然后返回一个新的函数,在这个新函数中调用原函数,并将this指向传入的对象,同时将bind方法传入的参数和新函数执行时传入的参数合并起来并传入原函数。
Function.prototype.myBind = function () {
const _func = this;
const _self = arguments[0];
const _arguments = Array.prototype.slice(arguments, 1);
return function () {
_func.apply(_self, _arguments.concat(arguments));
};
};
function kun(num1, num2) {
console.log(this.name, num1, num2);
}
kun(1, 2);
const my = {
name: "大帅逼",
};
const peng = kun.bind(my, 8);
peng(9);
8.手写防抖函数debounce
这个方法是用来解决高频事件触发时出现的性能问题的,它会等待一段时间后再执行函数,如果在这段时间内再次触发了事件,则重新计时。这个方法的实现思路就是在每次触发事件时清除上一次的定时器,然后设置一个新的定时器,等待一段时间后执行函数。
function myDebounce(func, delay = 500) {
if (typeof func !== "function" || typeof delay !== "number") {
throw new Error("func must be a function and delay must be a number");
}
let _code = null;
return function () {
clearTimeout(_code);
let _self = this;
_code = setTimeout(() => {
func.apply(_self, arguments);
}, delay);
};
}
const myFunc = myDebounce(function () {
console.log("嘿嘿嘿");
}, 2000);
window.onresize = myFunc;
9.手写节流函数throttle
这个方法也是用来解决高频事件触发时出现的性能问题的,它会在一段时间内只执行一次函数,如果在这段时间内再次触发了事件,则忽略这次触发。这个方法的实现思路就是设置一个标志位,用来记录是否可以执行函数,如果可以执行,则执行函数,并将标志位设置为false,然后在一段时间后将标志位重新设置为true,以便下一次可以执行函数。
function myThrottle(func, delay) {
if (typeof func !== "function" || typeof delay !== "number") {
throw new Error("func must be a function and delay must be a number");
}
let flag = true;
return function () {
let _self = this;
if (flag) {
func.apply(_self, arguments);
flag = false;
setTimeout(() => {
flag = true;
}, delay);
}
};
}
const myFunc = myThrottle(function () {
console.log("哈哈哈");
}, 2000);
window.onresize = myFunc;
暂时就写到这吧,如果有错误欢迎指出,如果有更好的方式也可以在评论区留言,下期再见