前端面试手撕代码-想入大厂这些必须会

instanceof

function myInstanceof(L,R){
    var LP = L.__proto__;
    var RP = R.prototype;
    while(true){
        if (LP == null){
            return false;
        }
        if (LP == RP){
            return true;
        }
        LP = LP.__proto__;
    }
}

call (重要)

Function.prototype.mycall = function(context){
    if (typeof this != 'function'){
        throw new TypeError("类型不正确")
    }
    context = context || window
    context.fn = this
    // 为什么从1开始截取?第一个参数不要了吗?
    // call的第一个参数是this指向的对象,并不是实际传入的参数
    let args = Array.from(arguments).slice(1)
    let res = context.fn(...args)
    delete context.fn
    return res
}

apply (重要)

Function.prototype.myApply = function(context){
    if (typeof this != 'function'){
        throw new TypeError('类型错误')
    }
    context = context || window
    context.fn = this
    let res
    if (arguments[1]){
        res = context.fn(...arguments[1])
    }else{
        res = context.fn()
    }
    delete context.fn
    return res;
}

bind (重要)

Function.prototype.bind = function(context){
    if (typeof this != 'function'){
        throw new TypeError('类型错误')
    }
    let _this = this
    // 这里用Array.prototype.slice.call是因为arguments是一个类数组,本身不存在slice方法,
    // 因此通过Array.prototype.slice来截取。
    // 由于截取后成了一个新数组,需要调用call将this指向原来的arguments并从1开始截取
    let args = Array.prototype.slice.call(arguments,1)
    return function F(){
    // 闭包,这里的this是调用闭包函数的对象,跟前面的this不同
        if(this instanceof F){
            return new _this(...args,...arguments)
        }else{
            return _this.apply(context,args.concat(...arguments))
        }
    }
}

new

function myNew(fn,...args){
    let obj = {}
    obj.__proto__ = fn.prototype
    let res = fn.apply(obj,args)
    // 这里的instanceof如何理解?
    // 其实就是看res是不是undefined或者null,如果是就返回新对象,不是就返回数值
    return res instanceof Object ? res : obj
}

浅拷贝和深拷贝 (重要)

var obj = {
    a: 1,
    b: {
        c: 2,
        h: '123',
        d: {
            e: 3,
            i: [1, 2, 3],
            f: {
                g: 4
            }
        }
    }
}
// 浅拷贝
var newObj = {
    ...obj
}
console.log(newObj);
var newObj2 = Object.assign({}, obj)
console.log(newObj2);

function copy(obj) {
    let newObj = {}
    for (let o in obj) {
        newObj[o] = obj[o]
    }
    return newObj
}
var newObj3 = copy(obj)
console.log(newObj3);

// 深拷贝
function isObject(obj){
// 解释一下什么是 Object.prototype.toString.call
// 一种获取对象类型的方式,实际上是调用了Object.prototype.toString方法,并将其this值设置为要检查类型的对象
// toString方法会返回一个表示对象类型的字符串。
// 但这个方法并不能判断自定义类型
    return Object.prototype.toString.call(obj) === '[object Object]' || Object.prototype.toString.call(obj) === '[object Array]'
}
function deepCopy(obj, map = new Map()){
	// 如果是基本数据类型,直接返回
    if (!isObject(obj)) return obj;
    // 如果map中已经存在了,直接返回map中的
    if (map.has(obj)) return map.get(obj)
    let newObj = Array.isArray(obj) ? [] : {}

    map.set(obj,newObj)
    for(let o in obj){
        if (isObject(obj[o])){
        	// 一个递归
            newObj[o] = deepCopy(obj[o], map)
        }else{
            newObj[o] = obj[o]
        }
    }
    return newObj
}
var deepNewObj = deepCopy(obj)
console.log(deepNewObj);
var deepNewObj2 = JSON.parse(JSON.stringify(obj))
console.log(deepNewObj2);

实现promise (重要)

class Promise {
    constructor(executor) {
        this.state = 'pending'
        this.reason = undefined
        this.value = undefined
        this.success = []
        this.faild = []

        let resolve = function (value) {
            if (this.state == 'pending') {
                this.state = 'fulfilled'
                this.value = value
                this.success.forEach(call => {
                    call()
                });
            }
        }
        let reject = function (reason) {
            if (this.state == 'pending') {
                this.state = 'reject'
                this.reason = reason
                this.faild.forEach(call => call())
            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onResolve, onReject) {
        if (this.state == 'fulfilled') {
            onResolve(this.value)
        } else if (this.state == 'reject') {
            onReject(this.reason)
        } else {
            this.success.push(() => onResolve(this.value))
            this.faild.push(() => onReject(this.reason))
        }
    }
}

Promise.all = function (promises) {
    let res = []
    let count = 0

    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(ans => {
                res[i] = ans
                count++
                if (count == promises.length) {
                    resolve(res)
                }
            }, reason => {
                reject(reason)
            })
        }
    })
}

Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(value => {
                resolve(value)
            },reason => {
                reject(reason)
            })
        }
    })
}

防抖与节流 (重要)

function debounce(fn,wait){
    let timer = null
    return function(){
        let args = arguments
        let context = this
        if (timer){
            clearTimeout(timer)
            timer = null
        }
        timer = setTimeout(()=>{
            fn.apply(context,args)
        },wait) 
    }
}
// 优化
function debounce(fn, wait, immediate) {
    let timer = null;
    return function () {
        let args = arguments;
        let context = this;
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
        if (immediate) {
            let callNow = !timer;
            timer = setTimeout(() => {
                timer = null;
            }, wait);
            if (callNow) {
                fn.apply(context, args);
            }
        } else {
            timer = setTimeout(() => {
                fn.apply(context, args);
            }, wait);
        }
    };
}

function throttle(fn,threshold){
    let timer = null
    return function(){
        let args = arguments
        let context = this
        if (!timer){
            timer = setTimeout(() => {
                fn.apply(context,args)
                timer = null
            },threshold)
            
        }
    }
}

函数柯里化

function add(...args) {
    function curryAdd(...curryArgs) {
        if (curryArgs.length === 0) {
            return args.reduce((total, num) => total + num);
        }
        return add(...args, ...curryArgs);
    }

    return curryAdd;
}

console.log(add(1, 2, 3)(4)()); // 10

单例模式

var singletom = (function(){
    let instance = null
    function createInstance(name){
        // 在这里写一些初始化的属性和方法
        var obj = {};
        obj.name = name
        return obj
    }
    return {
        getInstance(name){
            if (!instance){
                instance = createInstance(name)
            }
            return instance
        }
    }
})()
var a = singletom.getInstance('a')
var b = singletom.getInstance('b')
console.log(a);
console.log(b);
console.log(a===b);

观察者模式

class Subject{
    constructor(){
        this.observers = []
    }
    addObserver(observer){
        this.observers.push(observer)
    }
    removeObserver(observer){
        this.observers = this.observers.filter(ob => ob != observer)
    }
    notify(){
        this.observers.forEach(ob => {
            ob.callback()
        })
    }
}
class Observer {
    constructor(id,callback){
        this.id = id
        this.callback = callback
    }
}

let ob1 = new Observer(1,()=>{
    console.log("1已经收到消息");
})
let ob2 = new Observer(2,()=>{
    console.log("2已经收到消息");
})
let ob3 = new Observer(3,()=>{
    console.log("3已经收到消息");
})
let subject = new Subject()
subject.addObserver(ob1)
subject.addObserver(ob2)
subject.addObserver(ob3)
subject.removeObserver(ob2)
subject.notify()

消息订阅与发布 (重要)

class Pubsub{
    constructor(){
        this.event = {}
    }
    subscribe(topic,callback){
        if (!this.event[topic]){
            this.event[topic] = []
        }
        this.event[topic].push(callback)
    }
    cancel(topic,callback){
        if (!this.event[topic]){
            return;
        }
        this.event[topic] = this.event[topic].filter(call => call != callback)
    }
    publish(topic,content){
        this.event[topic].forEach(call => {
            call(content)
        });
    }
}
let pubsub = new Pubsub()
function use(content){
    console.log(content);
}
pubsub.subscribe('chatGPT',use)
pubsub.subscribe('cxk',content=>{
    console.log(content);
})
pubsub.cancel('chatGPT', use)
pubsub.publish('chatGPT',"知道了如何使用chatGPT")
pubsub.publish('cxk',"cxk打篮球")

数组拍平

const arr = ["1", ["2", "3"], ["4", ["5", ["6"]], "7"]]
// 默认只拍平一层
// console.log(arr.flat());
// [ '1', '2', '3', '4', [ '5', [ '6' ] ], '7' ]
// 按传递的参数拍平
// console.log(arr.flat(2));
// [ '1', '2', '3', '4', '5', [ '6' ], '7' ]
console.log(arr.flat(Infinity));
// [ '1', '2', '3', '4', '5', '6', '7' ]

let res1 = arr.toString().split(',').map(num => Number(num))
// console.log(res1);

let res2 = arr.join().split(',').map(num => Number(num))
// console.log(res2);

let res3 = (arr + '').split(',').map(num => Number(num))
console.log(res3);

数组方法

// forEach
Array.prototype.myForEach = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function!')
    }
    // 这里的self其实就是数组
    var self = this // a
    for(let i = 0; i < self.length; i++){
        // 回调函数可以传三个参数,分别是当前元素,当前元素下标,整个数组
        fn(self[i],i,self)
    }
}
var a = [1,2,3,4]
a.myForEach(num=>{console.log(num);})


// map
Array.prototype.myMap = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function')
    }
    let self = this
    let res = []
    for(let i = 0; i < self.length; i++){
        res[i] = fn(self[i],i,self)
    }
    return res
}
var a = [1,2,3,4]
var ans = a.myMap(num => num*2)
console.log(ans);


// filter
Array.prototype.myFilter = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function')
    }
    let self = this
    let res = []
    for(let i = 0; i < self.length; i++){
        fn(self[i],i,self) && res.push(self[i])
    }
    return res
}
var a = [1,2,3,4]
var ans = a.myFilter(num => num > 3)
console.log(ans);


// find
Array.prototype.myFind = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function')
    }
    let self = this
    for(let i = 0; i < self.length; i++){
        if (fn(self[i],i,self)){
            return self[i]
        }
    }
}
var a = [1,2,3,4]
var ans = a.myFind(num => num >= 3)
console.log(ans);


// every
Array.prototype.myEvery = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function')
    }
    let self = this
    for(let i = 0; i < self.length; i++){
        if (!fn(self[i],i,self)){
            return false
        }
    }
    return true
}
var a = [1,2,3,4]
var ans = a.myEvery(num => num >= 3)
console.log(ans);


// some
Array.prototype.mySome = function(fn){
    if (typeof fn != 'function'){
        throw new TypeError('not a function')
    }
    let self = this
    for(let i = 0; i < self.length; i++){
        if (fn(self[i],i,self)){
            return true
        }
    }
    return false
}
var a = [1,2,3,4]
var ans = a.mySome(num => num >= 3)
console.log(ans);

手写xhr发送请求

function Ajax(url){
    const p = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.onreadystatechange = function(){
            if (xhr.readyState === 4){
                if (xhr.status === 200){
                    resolve(JSON.parse(xhr.responseText))
                }
            }else if (xhr.status === 404){
                reject(new Error('404 Not Found'))
            }
        }
        xhr.send(null)
    })
    return p
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值