手写代码题

110 阅读4分钟

Q1:防抖函数

function debounce(fn, wait, immedidate) {
    // TODO
    let timer = nulll;
    return function(...args) {
        const context = this
        clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(context, args)
        }, wait)
    }
}

Q2:节流

function throttle(cb, delay) {
    let timer = null
    return function(...args) {
        if(timer) return 
        timer = setTimeout(() => {
            cb.apply(this, args)
            timer = null
        }, delay)
    }
}

Q3:给定一个只包括{}()[]的字符串,判断其是否有效

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合
  2. 左括号必须以正确的顺序闭合

示例1: s = '{}' // true

示例2: s = '{[]}' // true

示例3: s = '{' // false

示例4: s = '{[}]' // false

function isValid(str) {
    // TODO
    let res = true
    const mapStr = {
        "[":"]",
        "{":"}",
        "(":")",
    }
    for (var i = 0 ; i < str.length / 2 ; i++) {
        if(mapStr[str[i]] !== str[str.length-1-i]) return false
    }
    return res
}

Q4:找出字符串中最长连续子串

示例:

  1. "aaabbcc" // aaa
  2. "abc" // a
function fn(str) {
    let currentIdx = 1
    let maxIdx = 1
    let currentStr = str[0]
    let maxStr = str[0]
    
    for (let i = 1 ; i < str.length ; i++) {
        if(str[i] === str[i-1]) {
            currentStr += str[i]
            currentIdx++
        }  else {
            currentStr = str[i]
            currentIdx = 1
        }
        if(currentIdx > maxIdx){
            maxIdx = currentIdx
            maxStr = currentStr
        }
    }
    return maxStr
}

Q5:请手写实现一个简易的Ajax

function myAjax() {
    // 创建一个 XMLHttpRequest 对象
    const xhr = new XMLHttpRequest();

    // 设置请求的类型和 URL
    xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);

    // 设置请求头(可选)
    xhr.setRequestHeader('Content-Type', 'application/json');

    // 注册事件监听器,当请求状态变化时触发
    xhr.onreadystatechange = function () {
        // 检查请求是否完成
        if (xhr.readyState === 4) {
            // 检查请求是否成功
            if (xhr.status === 200) {
                // 解析响应文本
                const response = JSON.parse(xhr.responseText);
                // TODO
            } else {

            }
        }
    };

    // 发送请求
    xhr.send();
}

Q6:使用setTimeout实现setInterval

const mySetInterval = (cb, delay) => {
    cb()
    const intervalId = setTimeout(() => {
        // 清除前一个 setTimeout,防止在回调函数执行时间较长时产生累积的延迟      
        clearTimeout(intervalId);            
        // 递归调用 mySetInterval         
        mySetInterval(cb, delay);  
    }, 1000)
}
mySetInterval(() => console.log("Hello, setInterval"), 1000)

Q7:给定一个整数数组arr,其中有些元素出现两次而其他元素出现一次。找到所有出现两次的元素。你可以不用到任何额外空间并在o(n)时间复杂度内解决这个问题吗?

function fn(arr) {
    return arr.filter((num, index) => arr.indexOf(num) !== index);
}

同事说indexOf也是一次遍历,这里的时间复杂度是平方n

chatgpt给的答案如下:

function fn(arr) {
    const seen = new Set();
    const duplicates = new Set();
    
    for (const num of arr) {
        if (seen.has(num)) {
            duplicates.add(num);
        } else {
            seen.add(num);
        }
    }
    
    return Array.from(duplicates);
}

Q8:单位转换:后端返回一个数字,单位是kb,前端要展示成 KBMB 等形式。

function formatSizeUnits(kb) { 
    const sizeArr = ['KB', 'MB', 'GB', 'TB', 'PB'];
    let sizeIndex = 0;
    while(kb >= 1024 && sizeIndex < sizeArr.length) {
        kb = kb/1024;
        sizeIndex++;
    }
    return `${kb.toFixed(2)}${sizeArr[sizeIndex]}`
}
console.log(formatSizeUnits(55));
console.log(formatSizeUnits(1024));
console.log(formatSizeUnits(5201314));
console.log(formatSizeUnits(1073741824));

image.png

Q9: Array.prototype.flat()

function _flat(n = 1) {
    let res = [];
    if (!n) return this;

    for (let i = 0; i < this.length; i++) {
        if (Array.isArray(this[i])) {
            res = res.concat(_flat.call(this[i], n - 1)); // 使用 call 来调用 _flat
        } else {
            res.push(this[i]);
        }
    }

    return res;
}

Array.prototype.flat = _flat;

let arr = [1, 2, [3, 4, [5, 6, [7, 8]]], 9, 10];

console.log(arr.flat());    // 输出: [1, 2, 3, 4, [5, 6, [7, 8]], 9, 10]
console.log(arr.flat(2));   // 输出: [1, 2, 3, 4, 5, 6, [7, 8], 9, 10]
console.log(arr.flat(Infinity));   // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Q10:URL参数解析

function parseParam(url) {
    const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来
    const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中
    let paramsObj = {};
    // 将 params 存到对象中
    paramsArr.forEach(param => {
        if (/=/.test(param)) { // 处理有 value 的参数
            let [key, val] = param.split('='); // 分割 key 和 value
            val = decodeURIComponent(val); // 解码
            val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字
    
            if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值
                paramsObj[key] = [].concat(paramsObj[key], val);
            } else { // 如果对象没有这个 key,创建 key 并设置值
                paramsObj[key] = val;
            }
        } else { // 处理没有 value 的参数
            paramsObj[param] = true;
        }
    })
    
    return paramsObj;
}

Q11:startWith 与 indexOf 相互实现

indexOf 实现 startWith

const str = 'abc';

function _startWith(s) {
  return this.indexOf(s) === 0;
}

String.prototype.startsWith = _startWith;

console.log(str.startsWith('a'));
console.log(str.startsWith('ab'));
console.log(str.startsWith('b'));

image.png

startWith 实现 indexOf

const str = 'abc';

function _indexOf(s) {
  if (!s) return -1;
  let index = 0;
  let _str = this.toString();
  while (!_str.startsWith(s)) {
    index++;
    _str = _str.slice(1);
    if (!_str.length) {
      return -1;
    }
  }
  return index;
}

String.prototype.indexOf = _indexOf;

console.log(str.indexOf('bc'));
console.log(str.indexOf('ef'));

image.png

Q12:实现一个支持链式调用的类

class Haha {
    value = 0;
    add (num) {
        this.value += num;
        return this;
    }
    sub (num) {
        this.value -= num;
        return this;
    }
    getValue () {
        return this.value;
    }
}
console.log(new Haha().add(3).add(4).add(5).getValue()) // 12
console.log(new Haha().add(3).add(4).sub(5).getValue()) // 2

Q13:实现一个sum函数

支持

sum(2,3) // 5

sum(2)(3) // 5

const sum = (x, y) => {
    if(!y) {
        return function(y) {
            return x+y;
        }
    }
    return x+y;
} 

效果

image.png

Q14:统计数字

计算数字k在0到n中的出现的次数,k可能是0~9的一个值

例如n=12,k=1,在 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],我们发现1出现了5次 (1, 10, 11, 12)

const digitCounts = (n, k) => {
    let num = 0;
    for (let i = 0 ; i <= n ; i++) {
        if (String(i).indexOf(k) !== -1) {
            num += String(i).split(k).length - 1;
        }
    }
    return num;
}

console.log(digitCounts(12, 1)) // 5

image.png