前端面试手写代码题实在是我的一个弱项,加上面试时紧张会写不出来,下定决心要战胜它
只要把它背的像身份证号码一样熟,面试就不再怕了
所以总结了一下网上经典的、自己面试遇到过的手写代码题
每天亿遍~~ 早日战胜手写代码题
欢迎点赞收藏关注,后续会继续补充
目录
手写Promise、Promise.all、Promise.race
包括then、catch、all、race
/**
* @description 手写Promise
*/
class MyPromise {
state = 'pending' // 状态 'pending' 'fulfilled' 'rejected'
value = undefined // 成功后的值
reason = undefined // 失败后的值
resolveCallbacks = [] // pending状态下,成功的回调
rejectCallbacks = [] // pending状态下,失败的回调
constructor(fn){
const resolveHandler = (value) => {
if(this.state === 'pending'){
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn(this.value))
}
}
const rejectHandler = (reason) => {
if(this.state === 'pending'){
this.state = 'rejected'
this.reason = reason
this.rejectCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolveHandler, rejectHandler)
} catch(err) {
rejectHandler(err)
}
}
then(fn1, fn2){
// 当 pending状态下, fn1 和 fn2 会被存储到callbacks中
fn1 = typeof fn1 === "function" ? fn1 : (v) => v
fn2 = typeof fn2 === "function" ? fn2 : (e) => e
if(this.state === 'pending'){
const p1 = new MyPromise((resolve,reject) => {
this.resolveCallbacks.push(()=>{
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch(err){
reject(err)
}
})
this.rejectCallbacks.push(() => {
try {
const newReason = fn2(this.Reason)
reject(newReason)
} catch(err){
reject(err)
}
})
})
return p1
}
if(this.state === 'fulfilled'){
const p1 = new MyPromise((resolve,reject) => {
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch(err){
reject(err)
}
})
return p1
}
if(this.state === 'rejected'){
const p1 = new MyPromise((resolve,reject) => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch(err){
reject(err)
}
})
return p1
}
}
// 就是then的语法糖,简单模式
catch(fn) {
return this.then(null, fn)
}
}
MyPromise.resolve = function(value) {
return new MyPromise((resolve,reject) => {
resolve(value)
})
}
MyPromise.reject = function(reason) {
return new MyPromise((resolve,reject) => {
reject(reason)
})
}
MyPromise.all = function (promiseList = []) {
const p1 = new MyPromise((resolve,reject) => {
const result = []
const length = promiseList.length
let resolvedCount = 0
promiseList.forEach((p)=>{
p.then(data => {
result.push(data)
resolvedCount++ // 同理,resolvedCount 必须在then里进行++
// 这里不能用forEach 的 index来判断 index === length - 1,因为forEach不是一个异步循环,index会一下子增加到最大,而promiseList中的每一个promise还不一定执行完
if(resolvedCount === length){
// 已经遍历到最后一个promise
resolve(result)
}
}).catch(err => {
reject(err)
})
})
})
return p1
}
MyPromise.race = function(promiseList = []) {
let resolved = false // 标记
const p1 = new MyPromise((resolve,reject) => {
promiseList.forEach(p => {
p.then(data => {
if(!resolved){
resolve(data)
resolved = true
}
}).catch((err) => {
reject(err)
})
})
})
return p1
}
// 测试
let p4 = new MyPromise((resolve,reject) => {
setTimeout(() =>{
resolve(100)
},1000)
})
let p2 = new MyPromise((resolve,reject) => {
resolve(666)
})
MyPromise.all([p4,p2]).then((res) => {
console.log(res)
})
console.log(p1)
p1.then((res) => {
console.log(res)
})
p2.then((val) => {
console.log(val)
})
手写jsonp
(function (global) {
function jsonp (url, params, callback) {
let queryStringArr = [];
for (var k in params) {
queryStringArr.push(`${k}=${param[k]}`);
}
let random = Math.random().toString().replace('.', '');
let callbackFunctionName = 'jsonp_' + random;
queryStringArr.push(`callback=${callbackFunctionName}`);
let script = document.createElement('script');
script.src = url + '?' + queryStringArr.join('&');
document.body.appendChild(script);
global[callbackFunctionName] = function (param) {
callback(param);
document.body.removeChild(script);
};
}
global.jsonp = jsonp;
})(window);
手写instanceof
function myInstance(left, right) {
var proto = left.__proto__;
var prototype = right.prototype;
if (proto === null) {
return false;
} else if (proto === prototype) {
return true;
} else {
return myInstance(proto, right);
}
}
// test
var a = {};
console.log(myInstance(a,Array)); //false
console.log(myInstance({}, Object)) //true
手写call
Function.prototype.myCall = function(thisArg, ...args) {
const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window // 若没有传入this, 默认绑定window对象
thisArg[fn] = this // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args) // 执行当前函数
delete thisArg[fn] // 删除我们声明的fn属性
return result // 返回函数执行结果
}
//测试
foo.myCall(obj)
手写apply
Function.prototype.myCall = function(thisArg, args) {
const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window // 若没有传入this, 默认绑定window对象
thisArg[fn] = this // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args) // 执行当前函数
delete thisArg[fn] // 删除我们声明的fn属性
return result // 返回函数执行结果
}
//测试
foo.myCall(obj, [])
手写bind
Function.prototype.myBind = function(obj){
// 从arguments第2个开始是参数
var args = Array.prototype.slice.call(arguments,1)
var fn = this
// 返回一个绑定好的方法
return function(){
var newArgs = Array.prototype.slice.call(arguments)
// 可能存在foo.bind(obj,args)(newArgs),所以要把两个参数拼在一起
fn.apply(obj, args.concat(newArgs))
}
}
手写new
let newMethod = function(Parent, ...rest){
// 1、以构造器的prototype属性为原型,创建新对象
let child = Object.create(Parent.prototype)
// 2、将this(也就是上一句中的新对象)和调用参数传给构造器,执行
let result = Parent.call(child, ...rest)
// 3、如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象
return result instanceof Object ? result : child
}
let Parent = function (name, age) {
this.name = name;
this.age = age;
};
手写ES5继承
ES5继承需要使用组合继承 既要继承属性又要继承方法
// 父类
function Animal(name){
this.name = name
}
Animal.prototype.showName = function(){
console.log("这个动物的名字是"+this.name)
}
// 子类
function Dog(name,color){
Animal.call(this,name) // 只能继承属性
this.color = color
}
Dog.prototype = new Animal() // 原型继承
Dog.prototype.constuctor = Dog
let d1 = new Dog('doge','white')
console.log(d1) // Dog {name: "doge", color: "white"}
d1.showName() // 这个动物的名字是doge
手写防抖debounce
function debounce(func, delay) {
let timeout
return function() {
clearTimeout(timeout) // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。
timeout = setTimeout(() => {
func.apply(this, arguments)
}, delay)
}
}
手写节流throttle
function throttle(func, delay){
let run = true
return function(){
if(!run){
return
} else {
run = false
func.apply(this, arguments)
setTimeout(function(){
run = true
},delay)
}
}
}