文章目录
-
- 前言:
- 防抖
- 节流
- 函数柯里化
- 函数组合
- [instanceof 实现](#instanceof 实现)
- 实现new操作符的行为
- 深拷贝
- 继承实现:
- 手写Promise
- 数组中常见函数的实现
前言:
在前端面试中,经常会遇到要求手写的代码的题目,主要是考察我们的编程能力、和对JavaScript的理解以及对前端最佳实践的掌握。下面是我整理了一些常见的手写代码题目,您可以看看自己能实现哪些。。
防抖
防抖函数,确保一段时间内多次触发事件只执行一次。
js
// --- 基础版
function debounce(fn, delay) {
let timer = 0;
return (e) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => fn(e), delay);
};
}
let deboundceCli = debounce((e) => console.log(e), 500);
document.body.addEventListener("click", function () {
deboundceCli("执行了。");
});
js
// ---立即执行版
function debounceImmediate(fn, delay, immediate) {
let timer = null;
return (...rest) => {
if (timer) {
clearTimeout(timer);
}
// 立即执行
if (immediate) {
let exec = !timer;
timer = setTimeout(() => (timer = null), delay);
if (exec) {
fn(...rest);
}
} else {
timer = setTimeout(() => fn(...rest), delay);
}
};
}
let deboundceCli = debounceImmediate((e) => console.log(e), 500, true);
document.body.addEventListener("click", function () {
deboundceCli("执行了。");
});
节流
节流函数,确保在指定时间内只执行一次。
js
const throttle = (fn, delay) => {
let lastTimer = null;
return (e) => {
if (Date.now() - lastTimer > delay) {
lastTimer = Date.now();
fn(e);
}
};
};
let throttleCli = throttle((e) => console.log(e), 1000);
window.document.addEventListener("scroll", function () {
throttleCli("执行了。。 ");
});
函数柯里化
能够接受多个参数,并返回一个新的函数。
js
// ---柯里化
const curry = (fn) => {
return function inner() {
let len = arguments.length;
if (len === fn.length) {
// 执行
return fn(...arguments);
} else {
// 返回一个函数
return (...res) => inner(...[...arguments, ...res]);
}
};
};
const f1 = (a, b, c) => a * b * c;
let cy = curry(f1);
console.log(cy(2)(3, 4)); // 24
函数组合
接受多个函数,返回新的函数,执行结果是从右向左执行
js
// ---- 函数组合--- 从右向左执行
const group = (...rest) => {
return (val) => {
return [...rest].reduceRight((item, res) => {
return res(item);
}, val);
};
};
const f1 = (val) => val + 5;
const f2 = (val) => val * 10;
let res = group(f1,f2)
console.log(res(10)); // 105: (10*10) + 5
instanceof 实现
根据原型链向上查找,如果找到
null
都还没找到,就返回false
, 找到就返回true
js
const my_instanceof = (instance, obj) => {
let proto = instance.__proto__;
while (proto) {
if (proto.constructor.name === obj.name) return true;
proto = proto.__proto__;
}
return false;
};
let a = [];
console.log("instanceOf 结果:", my_instanceof(a, Array));
实现new操作符的行为
js
function myNew(fn, ...args) {
// 1. 创建一个空对象
let obj = Object.create(fn.prototype);
// 2. 调用构造函数,绑定this,并传入参数
let result = fn.apply(obj, args);
// 3. 如果构造函数返回了一个新的对象,则返回该对象;否则返回步骤1创建的对象
return result instanceof Object ? result : obj;
}
深拷贝
处理基本数据类型,对象、数组以及其中的嵌套结构
js
function deepClone(obj) {
// 如果是基本数据类型或null,则直接返回
if (obj === null || typeof obj !== "object") {
return obj;
}
// 如果是日期对象,则创建一个新的日期对象
if (obj instanceof Date) {
return new Date(obj);
}
// 如果是正则对象,则创建一个新的正则对象
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 创建一个新对象或数组,并存储在WeakMap中
const cloneObj = new obj.constructor();
// 递归拷贝原对象的每个属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 忽略原型链上的属性
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
继承实现:
手写Promise
数组中常见函数的实现
在 JavaScript 中,数组的函数式方法非常强大,它们允许你以声明式的方式处理数组数据.
设置全局变量numbers
js
const numbers = [1, 2, 3];
-
map :
map
方法创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值。javascriptArray.prototype.myMap = function (callback) { const newArray = []; for (let i = 0; i < this.length; i++) { newArray.push(callback(this[i], i, this)); } return newArray; }; const squares = numbers.myMap((number) => number * number); console.log(squares); // 输出 [1, 4, 9]
-
filter :
filter
方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。javascriptArray.prototype.myFilter = function (callback) { const newArray = []; for (let i = 0; i < this.length; i++) { if (callback(this[i], i, this)) { newArray.push(this[i]); } } return newArray; }; const evens = numbers.myFilter((number) => number % 2 === 0); console.log(evens); // 输出 [2]
-
reduce :
reduce
方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值,需要处理默认值
javascriptArray.prototype.myReduce = function (callback, initialValue) { let accumulator = initialValue !== undefined ? initialValue : this[0]; for (let i = initialValue !== undefined ? 0 : 1; i < this.length; i++) { accumulator = callback(accumulator, this[i], i, this); } return accumulator; }; const sum = numbers.myReduce( (accumulator, currentValue) => accumulator + currentValue ); console.log(sum); // 输出 6
-
forEach :
forEach
方法对数组的每个元素执行一次提供的函数。javascriptArray.prototype.myForEach = function (callback) { for (let i = 0; i < this.length; i++) { callback(this[i], i, this); } }; numbers.myForEach((number) => console.log(number)); // 输出: // 1 // 2 // 3
-
find :
find
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。javascriptArray.prototype.myFind = function (callback) { for (let i = 0; i < this.length; i++) { if (callback(this[i], i, this)) { return this[i]; } } return undefined; }; const found = numbers.myFind((number) => number > 1); console.log(found); // 输出 2
-
every :
every
方法测试所有元素是否都通过了测试函数。如果都通过,则返回 true;否则返回 false。javascriptArray.prototype.myEvery = function (callback) { for (let i = 0; i < this.length; i++) { if (!callback(this[i], i, this)) { return false; } } return true; }; const allAreNumbers = numbers.myEvery( (element) => typeof element === "number" ); console.log(allAreNumbers); // 输出 true
-
some :
some
方法测试数组中是不是至少有一个元素通过了被提供的函数测试。如果是,立即返回 true;否则返回 false。javascriptArray.prototype.mySome = function (callback) { for (let i = 0; i < this.length; i++) { if (callback(this[i], i, this)) { return true; } } return false; }; const anyAreEven = numbers.mySome((number) => number % 2 === 0); console.log(anyAreEven); // 输出 true
-
flat :
flat
方法将嵌套的数组"拍平",拍平的层级取决于输入的deep
深度
递归实现:
js
const flat = (arr, deep = 0) => {
let result = [];
if (deep === 0) return arr;
arr.forEach((item) => {
if (item instanceof Array) {
result = result.concat(flat(item, deep - 1));
} else {
result = result.concat(item);
}
});
return result;
};
console.log(flat([1, 2, [3, 4, [5, 6]]], 1)); // [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log(flat([1, 2, [3, 4, [5, 6]]], 2)); // [ 1, 2, 3, 4, 5, 6 ]
javascript
Array.prototype.myFlat = function (depth = 1) {
if (depth === 0) return this;
return this.reduce((acc, val) => {
return acc.concat(Array.isArray(val) ? val.myFlat(depth - 1) : val);
}, []);
};
const nestedArray = [1, [2, 3, [2, 4, [5]]]];
const flatArray = nestedArray.myFlat(2);
console.log(flatArray); // 输出 [1, 2, 3, 2, 4, Array(1)]
-
reduceRight :
reduceRight
方法对数组中的每个元素执行一个由您提供的 reducer 函数(从右到左执行),将其结果汇总为单个返回值。需要处理默认值
javascriptArray.prototype.myReduceRight = function (callback, initialValue) { let accumulator = initialValue !== undefined ? initialValue : this[this.length - 1]; let start = initialValue !== undefined ? this.length - 1 : this.length - 2; for (let i = start; i >= 0; i--) { accumulator = callback(accumulator, this[i], i, this); } return accumulator; }; const rightSum = numbers.myReduceRight( (accumulator, currentValue) => accumulator + currentValue ); console.log(rightSum); // 输出 6