前端手写题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

最近24届秋招也在如火如茶地进行中,小编也是在实习之余,利用有限的时间来准备秋招,今天分享前端几个常见的手写题:


一、Promise.all

/**
 * 
 * @param {*} promises 
 * @returns 
 * Promise.all(iterable) 方法返回一个 Promise 实例,
 * 此实例在 iterable 参数内所有的 promise 都“完成(resolvedresolved)”或
 * 参数中不包含 promise 时回调完成(resolveresolve);如果参数中 promise
 *  有一个失败(rejectedrejected),此实例回调失败(rejectreject),
 * 失败的原因是第一个失败 promise 的结果。

 */

function promiseAll(promises) {
    return new Promise((resolve,reject)=> {
        if(!Array.isArray(promises)) {
            return reject(new TypeError('arguments must be an array'))
        }
        var resolvedCounter = 0
        var promiseNum = promises.length;
        var resolvedValues = new Array(promiseNum);

       for(let i = 0; i < promiseNum; i++) { 
            (function(i){
                Promise.resolve(promises[i]).then(function(value){
                    resolvedCounter++
                    resolvedValues[i] = value
                    if(resolvedCounter == promiseNum) {
                        return resolve(resolvedValues)
                    }
                },function(reason){
                    console.log(reason);
                    reject(reason)
                })
            })(i)
       }
    })
}


var p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);
promiseAll([p1,p2,p3]).then(function(res) {
    console.log(res);
})
Promise.all([p1,p2,p3]).then(function(res) {
    console.log(res);
})

二、防抖函数

// 改进
export function debounce<Fn extends Function>(fn:Fn, delay:number,immediate = false) {
    let timeout: number | undefined
    const debounced = function(args:any) {
        const later = () => {
            timeout = undefined
            if(!immediate) {
                fn.apply(null,args)
            }
        }
        // 判断是否立即执行
        const callNow = immediate && !timeout // timeout没有意味着还没有计时器
        clearTimeout(timeout)
        timeout = setTimeout(later,delay)
        // 如果需要立即执行,则立即执行
        if(callNow) {
            fn.apply(null, args)
        }
    }
    debounced.cancel = function() {
        clearTimeout(timeout)
        timeout = undefined
    }   
}

三、节流

export function throttle<Fn extends Function>(fn:Fn, delay:number, immediate = false) {

    // 最后一次执行的时间
    let last = Date.now()

    return function (args:any) {
        // 当前时间
        let now = Date.now()
        //当前距离上一次执行的时间大于间隔时间 
        if(now - last >= delay) {
            fn.apply(null, args)
            last = now
        }
    }
}

四、数据扁平化

var arr = [1, [2, [3, 4]]];
const res = [];
function flatten(arr) {
  arr.map((item) => {
    if (Array.isArray(item)) {
      flatten(item);
    } else {
      res.push(item);
    }
  });
  return res;
}

function flattens(arr) {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
}

//console.log(flatten(arr));
//console.log(flattens(arr));
console.log([].concat(...arr));
// 原地解法
const arr1 = [0, 1, 2, [[[3, 4]]]];

console.log(arr1.flat(3)); // 3 代表数组内最多嵌套层数
// expected output: [0, 1, 2, 3, 4] 

五、简单手写Vue双向数据绑定

class Vue {
  constructor(options) {
    this.$options = options
    this.$data = options.data

    // 对data做响应式处理
    observe(this.$data)
    // 代理data到vm上
    proxy(this)

    //执行编译
    new Complie(options.el, this)
  }
}
//对data选项执行响应式具体操作

function observe(obj) {
  if (typeof obj !== "object" || obj == null) {
    return
  }
  new Observer(obj)
}

class Observer {
  constructor(value) {
    this.value = value
    this.walk(value)
  }
  walk(obj) {
    Object.keys(obj).forEach((key) => {
      defineReactive(obj, key, obj[key])
    })
  }
}

// 编译过程
class Compiler {
    constructor(el,vm) {
        this.$vm = vm
        this.$el = document.querySelector(el) // 获取dom元素
        if(this.$el) {
            this.compile(this.$el)
        }
    }
    compile(el) {
        const childNodes = el.childNodes
        Array.from(childNodes).forEach(node => {
            if(this.isElement(node)) {  //判断是否为节点
                console.log("编译元素" + node.nodeName);
            }
            else if (this.isInterpolation(node)) {
                console.log('编译插值文本' + node.textContent); // 判断是否为插值文本 {{}}
            }
            if(node.childNodes && node.childNodes.length > 0) {  // 判断是否有子元素
                this.compile(node) // 对子元素进行递归遍历 
            }
        })
    }
    isElement(node) {
        return node.nodeType == 1
    }
    isInterpolation(node) {
        return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent)
    }
}

// 负责更新视图
class Watcher {
    constructor(vm,key,updater) {
        this.vm = vm
        this.key = key
        this.updateFn = updater
        // 创建实例时,把当前实例指定到Dep.target静态属性上
        Dep.target = this
        // 读一下key ,触发get
        this.vm[this.key]
        // 置空
        Dep.target = null
    }

    // 未来执行dom更新函数,由dep调用
    update() {
        this.updateFn.call(this.vm,this.vm[this.key])
    }
}
// 声明一个Dep
class Dep {
    constructor() {
        this.deps = []
    }
    addDep(dep){
        this.deps.push(dep)
    }
    notify() {
        this.deps.forEach((dep)=> dep.update())
    }
}

// 依赖收集创建Dep实例

function defineReactive(obj,key,val) {
     this.observe(val)
     const dep = new Dep()
     Object.defineProperty(obj, key, {
        get() {
            Dep.target && dep.addDep(Dep.target)  // Dep.target也就是Watcher实例
            return val
        },
        set(newVal) {
            if(newVal === val) return
            dep.notify() // 通知dep执行更新方法
        }
     })
}


六、手写深拷贝

在这里插入图片描述

七、手写call

在这里插入图片描述

八、实现LPU缓存算法

class LRUCache {
    #map; // 私有属性
    #length; // 私有属性
    constructor(length) {
        this.#map = new Map()
        this.length = length
    }

    get(key) {
        if(!this.#map.has(key)) {
            return
        }
        const value = this.#map.get(key)
        // 删除之前的数据
        this.#map.delete(key)
        // 再把数据加进去
        this.#map.set(key,value)
        return value
    }

    set(key,value) {
        // 如果之前有这条数据,就删掉
        if(this.#map.has(key)) {
            this.#map.delete(key)
        }
        // 统一变成添加行为
        this.#map.set(key,value)
        if(this.#map.size > this.#length) {
            const firstKeyValue = this.#map.keys().next().value
            // 如果大于最大长度,我们需要删除第一个key值
            this.#map.delete(firstKeyValue)
        }
    }
}

总结

以上就是今天要讲的内容,期望大家秋招都能成功拿到心仪的offer!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 实现一个数组去重的函数 思路:使用对象来存储数组中的元素,遍历数组,若元素在对象中不存在,则存储到对象中,并将其推入新数组中。 2. 实现一个函数,判断一个字符串是否是回文字符串 思路:将字符串翻转,与原字符串比较是否相等。 3. 实现一个函数,可以将多维数组转化为一维数组 思路:使用递归来遍历多维数组,将每个元素推入新数组中,直到遍历完所有元素。 4. 实现一个函数,统计一个字符串中出现次数最多的字符 思路:使用对象来存储每个字符出现的次数,遍历字符串,将每个字符存储到对象中,找到出现次数最多的字符。 5. 实现一个函数,实现数组的冒泡排序 思路:使用双重循环遍历数组,比较相邻两个元素的大小,如果前者大于后者,则交换两个元素的位置,直到遍历完数组。 6. 实现一个函数,实现数组的快速排序 思路:选择数组中的一个元素作为基准点,将数组分为两个部分,一部分大于基准点,一部分小于基准点,递归处理两个部分。 7. 实现一个函数,实现数组的深拷贝 思路:使用递归遍历数组中的每个元素,判断元素类型,如果是对象或数组,则进行深拷贝,如果是基本类型,则直接复制。 8. 实现一个函数,实现函数的柯里化 思路:使用闭包保存参数,当参数个数达到预设值时,执行函数。 9. 实现一个函数,实现函数的节流 思路:使用定时器来控制函数执行的频率,每次函数执行时,清除定时器并重新设置一个定时器。 10. 实现一个函数,实现函数的防抖 思路:使用定时器来延迟函数执行,每次函数执行时,清除定时器并重新设置一个定时器。如果在定时器延迟时间内再次触发函数,则重新计时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bin_123ge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值