前端面试必备:手写题合集
ps:此部分是一面高频手写题,后续会看情况继续整理高频的手写题2.0版本,希望正在找工作的小可爱们都能顺顺利利的入职自己心仪的岗位,和可爱的同事一起共事~笔芯💗
一、防抖和节流
防抖,高频事件触发后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
function debounce(fn, timing){
let timer;
return function(){
clearTimeout(timer);
timer = setTimeout(()=>{
fn();
}, timing);
}
}
节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行效率。
function throttle(fn, timing){
let trigger;
return function(){
if(trigger) return;
trigger = true;
fn();
setTimeout(()=>{
trigger = false;
}, timing);
}
}
小tips:防抖靠定时器控制,节流靠变量控制
二、手写call、apply、bind
call()、apply()、bind()都是用来重定义this这个对象的,bind()返回的是一个新函数,你必须调用它才会被执行。
- call
Function.prototype.mycall = function (context, ...args){
const new_this = context || window;
const func = Symbol('func');
new_this[func] = this;
const res = new_this[func](...args);
delet new_this[func];
return res;
}
- apply
Function.prototype.myApply = function (context, args){
if(!(args instanceof Array)){
throw new TypeError(`args is not an array!`)
}
const new_this = context || window;
const func = Symbol('func');
new_this[func] = this;
const res = new_this[func](...args);
delet new_this[func];
return res;
}
- bind(使用apply实现)
Function.prototype.my_bind = function (context, ...args){
const new_this = context || window;
const fn = this;
return function (){
return fn.apply(new_this, args)
}
}
三、实现sleep函数
sleep函数作用是让线程休眠,等到指定时间在重新唤起
//方法一
function sleep1(ms, callback){
setTimeout(callback, ms)}
sleep1(1000, ()=>{
console.log(1000)
})
//方法二
function sleep2(ms){
return new Promise(function(resolve, reject){
setTimeout(resolve, ms)
})
}
sleep2(1000).then(()=>{
console.log(1000)
})
//方法三
function sleep3(ms){
return new Promise(function(resolve, reject){
setTimeout(resolve, ms)
})
}
async function init(){
await sleep3(1000);
}
init().then(()=>{
console.log(3000)
})
四、实现Promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
var _this = this
this.state = PENDING; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败原因
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
function resolve(value) {
if(_this.state === PENDING){
_this.state = FULFILLED
_this.value = value
_this.onFulfilled.forEach(fn => fn(value))
}
}
function reject(reason) {
if(_this.state === PENDING){
_this.state = REJECTED
_this.reason = reason
_this.onRejected.forEach(fn => fn(reason))
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=>v
onRejected = typeof onRejected === 'function' ? onRejected : r=>{throw r}
if(this.state === FULFILLED){
onFulfilled(that.value)
}
if(this.state === REJECTED){
onRejected(that.value)
}
if(this.state === PENDING){
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
};
五、实现Promise.all
Promise.prototype.myAll = function(iterators) {
const promises = Array.from(iterators)
const num = promises.length
let count = 0
let resolvedValue = new Array(num)
return new Promise((resolve, reject) => {
for(let item of promises){
Promise.resolve(item)
.then(data => {
resolvedValue[count++] = data
// 通过计数器,标记是否所有实例均 fulfilled
if(count === num){
resolve(resolvedValue)
}
})
.catch(err => reject(err))
}
})
}
六、实现Promise.race
Promise2.race = function(arrP) {
let hasValue = false
let hasError = false
return new Promise2((resolve, reject) => {
for(let i = 0; i < arrP.length; i++) {
arrP[i].then(data => {
!hasValue && !hasError && resolve(data)
hasValue = true
}, error => {
!hasValue && !hasError &&reject(error)
hasError = true
})
}
})
}
七、数组去重
// 先说数组去重,主要考察实现的方案要多元化。
//1、利用splice()
var arr = [1,23,1,1,1,3,23,5,6,7,9,9,8,5,5,5,5];
function norepeat(arr) {
for(var i = 0; i < arr.length-1; i++){
for(var j = i+1; j < arr.length; j++){
if(arr[i]==arr[j]){
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr2 = norepeat(arr);
//2、借助新数组,indexOf
var arr = [1,23,1,1,1,3,23,5,6,7,9,9,8,5];
function norepeat(arr){
var temp =[];
for(var i=0;i<arr.length;i++){
if(arr.indexOf(arr[i]) == i){
temp.push(arr[i]);
}
}
return temp;
}
//3、利用filter()
var arr = ["apple","banana","pear","apple","orange","orange"];
var arr2 =arr.filter(function(value,index,self){
return self.indexOf(value) ===index;
});
//4、利用空对象
var obj={};
var arr2=[];
for(var i=0;i<arr.length;i++){
if(!obj[arr[i]]){
obj[arr[i]]=true;
arr2.push(arr[i]);
}
}
八、实现一个url分析函数 可以增加参数,可以删除参数
var jsUrlHelper = {
getUrlParam : function(url, ref) {
var str = "";
// 如果不包括此参数
if (url.indexOf(ref) == -1)
return "";
str = url.substr(url.indexOf('?') + 1);
arr = str.split('&');
for (i in arr) {
var paired = arr[i].split('=');
if (paired[0] == ref) {
return paired[1];
}
return "";
},
putUrlParam : function(url, ref, value) {
// 如果没有参数
if (url.indexOf('?') == -1)
return url + "?" + ref + "=" + value;
// 如果不包括此参数
if (url.indexOf(ref) == -1)
return url + "&" + ref + "=" + value;
var arr_url = url.split('?');
var base = arr_url[0];
var arr_param = arr_url[1].split('&');
for (i = 0; i < arr_param.length; i++) {
var paired = arr_param[i].split('=');
if (paired[0] == ref) {
paired[1] = value;
arr_param[i] = paired.join('=');
break;
}
}
return base + "?" + arr_param.join('&');
},
delUrlParam : function(url, ref) {
// 如果不包括此参数
if (url.indexOf(ref) == -1)
return url;
var arr_url = url.split('?');
var base = arr_url[0];
var arr_param = arr_url[1].split('&');
var index = -1;
for (i = 0; i < arr_param.length; i++) {
var paired = arr_param[i].split('=');
if (paired[0] == ref) {
index = i;
break;
}
}
if (index == -1) {
return url;
} else {
arr_param.splice(index, 1);
return base + "?" + arr_param.join('&');
}
}
};
九、写一个函数,可以控制最大并发数
//promise方式
function sendResquest(urls, max, callback) {
let pending_count = 0, //并发数
idx = 0;//当前请求的位置
while (pending_count < max) {
_fetch(urls[idx++])
}
async function _fetch(url) {
if (!url) return;
pending_count++;
console.log(url + ':start','并发数: '+pending_count);
await fetch(url)
pending_count--;
console.log(url + ':done','并发数: '+pending_count);
_fetch(urls[idx++]);
pending_count || callback && callback()
}
}
十、实现instanceof
function instance_of(L: Object, R: any){
let protoChain = Object.getPrototypeOf(L);
const Lprototype = R.prototype;
while(protoChain) {
if(protoChain === Lprototype) {
return true;
}
protoChain = Object.getPrototypeOf(protoChain);
}
return false;
}
十一、实现new
// new一个对象的过程
// 创建一个新对象
// this指向这个新对象
// 执行代码,即对this赋值
// 返回this
function New(f) {
return function () {
var o = {"__proto__": f.prototype};
f.apply(o, arguments);//继承父类的属性
return o; //返回一个Object
}
}
十二、实现数组flat、fillter等方法
// 数组扁平化Array.prototype.flat() 特性,数组拍平方法也叫做数组扁平化、数组拉平、数组降维
// 不传入参数时,默认拉平一层 ,可以传入一个整数,表示想要拉平的层数
// <=0 返回原数组 , Infinity关键字作为参数时,无论多少层都会拉平转化为一维数组
// 1、 concat + 递归
function flat(arr) {
let arrResult = [];
arr.forEach(item => {
if (Array.isArray(item)) {
arrResult = arrResult.concat(arguments.callee(item)); // 递归
// 或者用扩展运算符
// arrResult.push(...arguments.callee(item));
} else {
arrResult.push(item);
}
});
return arrResult;
}
// 用reduce实现
const flat = arr => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flat(cur) : cur);
}, []);
};
十三、函数 curring
function curry(fn: any) {
return function judgeCurry(...args: any) {
return fn.length > args.length ?
(...args1: any) => judgeCurry(...args,...args1):
fn(...args);
}
}