手写题

80 阅读3分钟

实现一个批量请求函数, 能够限制并发量?

function requestLimit(urls, max) {
    const result = []
    let count = 0; // 当前请求完成的数量
    let index = 0; // 下一个请求的下标
    return new Promise(resolve => {
        if (urls.length === 0) {
            resolve([])
            return;
        }
        // 发送请求
        const request = async () => {
            if (index === urls.length) {
                return;
            }
            let url = urls[index]
            let i = index
            index++
            try {
                const res = await fetch(url)
                result[i] = res
            } catch (error) {
                result[i] = error
            } finally {
                //判断是否所有请求都完成
                count++
                if (count === urls.length) {
                    resolve(result)
                }
                request()
            }
        }
        for (let i = 0; i < Math.min(max, urls.length); i++) {
            request()
        }
    })
}



requestLimit(new Array(100).fill('https://api.uomg.com/api/rand.qinghua?format=json'), 3).then(value => {
    console.log('value :>> ', value);
})

手写new操作符

function myNew(fn,...args){
    if(typeof fn !== 'function'){
        throw 'fn must be function'
    }
    let obj = {}
    obj.__proto__ = fn.prototype
    let result  = fn.apply(obj,args)
    if(typeof result === 'object' && result !== null || typeof result === 'function'){
        return result
    } else {
        return obj
    }
}

let Person = function (name, age) {
    this.name = name
    this.age = age
    // return [1, 2]
}
Person.prototype.showInfo = function () {
    console.log(this.name + ': ' + this.age);
}

let p1 = myNew(Person, 'jerry', 7)
console.log(p1);   
p1.showInfo(); //jerry: 7

let p = new Person('tom', 5)
console.log(p);
p.showInfo();

实现一个use state

const useState = defaultValue => {
    const value = useRef(defaultValue);
    
    const setValue = newValue => {
        if (typeof newValue === 'function') {
            value.current = newValue(value.current);
        } else {
            value.current = value;
        }
    }
    
    //  触发组件的重新渲染
    dispatchAction();
    
    return [value, setValue];
}

实现一个拼手气抢红包算法

class RedPackage {
    money = 0;
    count = 0;
    _remain = 0;
    
    constructor(money, count) {
        this.money = money;
        this.count = count;
        this._remain = money;
    }
    
    openRedPackge() {
        //  已经抢完了
        if (this.count <= 0) {
            console.log('红包已经被抢完啦~');
            return;
        }
        
        //  只剩一个红包
        if (this.count === 1) {
            this.count--;
            console.log(this._remain);
            return;
        }
        
        const ratio = Math.random() * (this._remain / this.money);
        //  这里会涉及到一个JS计算精度的问题
        //  正常应该用第三方库或者字符串算法实现一个精准的加减乘除
        //  这里为了简单就这么直接做了
        let youGet = (this.money * ratio).toFixed(2);
        const tempRemain = +(this._remain - youGet).toFixed(2);
        const allLeast = this.count * 0.01;
        
        //  如果剩余的金额不够每人一分钱,那么需要减少本次获得的金额
        if (tempRemain < allLeast) {
            youGet = +(this._remain - allLeast).toFixed(2);
            this._remain = allLeast;
        } else {
            this._remain = tempRemain;
        }
        console.log(youGet);
        this.count--;
    }
}

给数字加分割逗号

function toString(num) {
    //  这是最简单的写法
    //  return num.toLocaleString();
    const result = [];
    const str = `${num}`.split('').reverse();
    for (let i = 0; i < str.length; i++) {
        if (i && i % 3 === 0) {
            result.push(',');
        }
        result.push(str[i]);
    }
    return result.reverse().join('');
}

手写题:计算树的最大深度(这个题可参考二叉树的最大深度,道理一样)

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */
// 用递归 时间复杂度O(n),空间复杂度O(hight),其中hight复杂度取决于树的高度,递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度。
function maxDepth(root: TreeNode | null): number {
    return root === null ? 0: Math.max(maxDepth(root.left),maxDepth(root.right)) + 1
};



手写题:实现一个类似es6模版字符串解析的功能

输出两个日期之间的所有日期

实现一个节流函数?如果想要最后一次必须执行的话怎么实现?

搜索内容切换为正则

 // 搜索内容切换为正则
 _getSearchReg = (val: string) => {
   const characters = [...'\\[]()?.+*^${}:'].reduce((charSet: any, c:string) => {charSet[c] = true; return charSet}, {});
   const _searchVal = val.split('').map(s => characters[s] ? `\\${s}` : s).join('');
   const matchReg = new RegExp(_searchVal, 'gm');
   return matchReg;
 }

手动封装一个请求函数,可以设置最大请求次数,请求成功则不再请求,请求失败则继续请求直到超过最大次数

image.png

编写一个自定义事件类,包含on/off/emit/once方法

image.png

红灯3秒亮一次,绿灯1秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?(用Promise实现)三个亮灯函数已经存在:

image.png

实现 mergePromise 函数,把传进去的数组按顺序先后执行,并且把返回的数据先后放到数组 data 中

`const timeout = ms => new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, ms); });

const ajax1 = () => timeout(2000).then(() => { console.log('1'); return 1; });

const ajax2 = () => timeout(1000).then(() => { console.log('2'); return 2; });

const ajax3 = () => timeout(2000).then(() => { console.log('3'); return 3; });

const mergePromise = ajaxArray => { // 在这里实现你的代码

};

mergePromise([ajax1, ajax2, ajax3]).then(data => { console.log('done'); console.log(data); // data 为 [1, 2, 3] });`

`// 要求分别输出 // 1 // 2 // 3 // done // [1, 2, 3]`

结果:

image.png

封装一个异步加载图片的方法

image.png

用Promise实现延迟3秒后输出 delay(3000).then(f,e)

image.png

上传图片和预览实现

image.png 预览:

image.png

有序数组合并

image.png

image.png

image.png

实现一个每秒输出hello world的函数,要求第三次输出后停止,用闭包实现

image.png

设计一个简单的任务队列,要求分别在1,3,4秒后打印出”1“,”2“,”3“

image.png

给定一个升序整数数组[0,1,2,4,5,7,13,15,16],找出其中连续出现的数字区间如下

image.png

请列举 html5 本地存储( localStorage )相关 api ,并实现 getAll 方法,获取本地存储

image.png

JS 截取地址栏指定字符后的内容

image.png