常见面试题收集

99 阅读4分钟

1.js 处理并发请求

要请求100次,只能有n个请求同时进行,怎么处理

简单代码实现

function myRequest(totalArr, n){
    let count = 0;
    let len = totalArr.length;
    let successNumber = 0;
    (function httpRequest(){
        if(count < n && totalArr.length>0){
            imgArr.shift();
            count++;
            setTimeout(res => {
                count --;
                successNumber ++ 
                httpRequest()
                if(successNumber === len){
                    console.log('结束')
                }
            },100)
        }
    })()
}

myRequest([1,2,4,5,6], 2)

思路

  1. 用一个count记录当前正在请求的数量。
  2. 用一个递归函数(下一步用到),里面循环调用请求,每发送一次请求,count加1,当count达到给定限定值时停止调用
  3. 在调用返回的时候count减少一,回调递归函数

2.实现一个函数加载js

代码实现

function loadJS(url) {
    return new Promise(resolve => {
        let script = document.createElement('script')
        script.src = url
        script.onload = function () {
            console.log('success')
            resolve('get')
        }
        document.querySelector('head').appendChild(script)
    })
}
loadJS('./index.js').then(res => {
    console.log(res)
})

3. jsonp 实现

代码实现

function callbackFunction(result, methodName) {
    var html = '<ul>';
    for(var i = 0; i < result.length; i++)
    {
        html += '<li>' + result[i] + '</li>';
    }
    html += '</ul>';
    document.getElementById('divCustomers').innerHTML = html;
}

function jsonp(url, params, callback) {
    let script = document.createElement('script')
    script.src = url + '?jsoncallback='+callback.name
    document.querySelector('head').appendChild(script)
}
jsonp('https://www.runoob.com/try/ajax/jsonp.php', '', callbackFunction)

4. js实现深拷贝

function deepCopy(target) {
    // 深拷贝不一定拷贝的都是对象,可以拷贝任何东西
    // 只有数组和对象需要递归获取,其它直接返回
    const type = Object.prototype.toString.call(target)
    if(type !== '[object Object]' || type !== '[object Array]' || type === '[object Null]'){
        return target
    }
 
    // 经过上面的判断,这里的就都是对象了(对象和数组)
    let newObj
    if(Object.prototype.toString.call(target) === '[object Object]'){
        newObj = Object.create(null)
    } else {
        newObj = []
    }
 
    Object.keys(target).forEach(key => {
        if(target.hasOwnProperty(key)){
            newObj[key] = deepCopy(target[key])
        }
    })
 
    return newObj
}

5. 比较两个值是否相等

可以比较任何值,可以使基本数据类型和引用数据类型,代码如下

function ifEqual(target1, target2) {
    let t1Type = Object.prototype.toString.call(target1)
    let t2Type = Object.prototype.toString.call(target2)
    if (t1Type !== t2Type) {
        return false
    }
    if (t1Type === '[object Null]') {
        return true
    }
    if (t1Type === '[object Undefined]') {
        return false
    }
 
    if (t1Type === '[object Object]' || t1Type === '[object Array]') {
        let keys1 = Object.keys(target1)
        let keys2 = Object.keys(target2)
        if (keys1.length !== keys2.length) {
            // 如果相比对象的keys长度不同,不相等
            return false
        }
        let result
        for(let i=0;i<keys1.length;i++){
            if (!ifEqual(target1[keys1[i]], target2[keys1[i]])){
                result = false
            }
        }
        return result
    } else {
        return target1 === target2
    }
}

6. 函数柯里化2

function rawMethod(a) {
    return a + 1;
}
function middleware1(next) {
    return function(a) {
        return next(a) + 1;
    };
}
function middleware2(next) {
    return function(a) {
        return next(a) + 1;
    };
}
function middleware3(next) {
    return function(a) {
        return next(a) + 1;
    };
}
 
// 请实现该方法
const applyMiddleWare = (originalMethod, ...args) => {
    // 请实现该方法
    const applyMiddleWare = (originalMethod, ...args) => {
        // 根据题目,需要如下处理函数:middleware3(middleware2(middleware1(rawMethod)))(n)
        // 这个函数层层嵌套,那么可以使用数组的reduce方法
        // 查看执行顺序,和reduce的顺序,这里除了第一个函数外,需要取相反方向,不能用sort,会改变原数组
 
        /*
        let funs = [].concat(originalMethod,args);
        let initFn = funs[0]
        let otherFn = []
        for(let i=funs.length-1;i>0;i--){
            otherFn.push(funs[i])
        }
        return otherFn.reduce((result, current) => {
            return current(result)
        },initFn)
        */
 
        // 上过面的方法只要执行 applyMiddleWare 就已经执行了他的参数方法
        // 所以 applyMiddleWare(newMethod, middleware1) 这里的23先于1执行
        // 那么就考虑将参数方法在包一层,在函数调用里执行
        let funs = [].concat(originalMethod,args)
        const len = funs.length
        if(len === 0){
            return arg => arg;
        }else if(len === 1){
            return funs[0]
        }else{
            return funs.reduce((a, b) => {
                return (n)=> {
                    return b(a)(n)
                }
            })
        }
    }
}
 
// 上面函数实际上返回如下
let z1 = n => middleware1(n => middleware2(n => middleware3(rawMethod)(n))(n))(n)
// 1. n => 里面函数结果 + 1
// 2. 里面函数结构 = 里面函数结构 + 1
// 3. 里面函数结构 = 里面函数结构 + 1 ...
// 4. 到了 rawMethod, rawMethod(n) + 1 + 1 + 1 
 
console.log(z1(1))
 
var newMethod = applyMiddleWare(rawMethod, middleware3, middleware2)
// 调用顺序:middleware2 -> middleware3 -> rawMethod,结果:x=3
var x = newMethod(1)
console.log(x)
 
var newMethod2 = applyMiddleWare(newMethod, middleware1);
// 调用顺序:middleware1 -> middleware2 -> middleware3 -> rawMethod,结果:y=13
var y = newMethod2(10)
console.log(y)

7. 求某数在数组中最后出现的位置

实现一个函数,返回指定数在有序数组中最后出现的位置,要求时间复杂度O(logn)

7-1. 实现方式1

思路:

  1. 要求复杂度O(logn)那么就要不能使用简单的for循环,for循环时间复杂度O(n)
  2. 使用夹逼方式查找方式时间复杂度可以
  3. 夹逼方式简单介绍
    • 分别取最大最小和中间值
    • 查找目标如果在小到中,继续从小到中区间里面找,最大索引切换到中
    • 同理,如果目标在中和大中间,继续从中到大区间找,最小缩影切换到中
    • 不断重复,知道找到
    • 目标等于小中大看情况做处理,这里因为找最后的位置,目标大等于中是就从中后面查找。

代码实现如下

function findLastIndex(arr, target) {
    const len = arr.length;
    let left = 0,
        right = len - 1;

    while (true) {
        if (arr[left] > target || arr[right] < target) return -1;

        if (arr[right] === target) {
            return right;
        }

        if (left + 1 == right && arr[left] === target) {
            return left;
        }

        let middle = Math.floor((right - left) / 2 + left);
        if (arr[middle] <= target) {
            left = middle;
        } else if (arr[middle] > target) {
            right = middle;
        }
    }
}
console.log(findLastIndex([1,2,3,3,3,4,5,7,8], 4));

最多一直查到左右两个碰到一起

7-2. 实现方式2

实际上就是取中间值使用了移位运算移动的是二进制,刚好结果就为需要的中间值

const findLastIndex = (nums, target) => {
    const len = nums.length;
    if (len < 1) return -1;
    let l = 0,
        r = len;
    while (l < r) {
        const mid = (l + r) >> 1;
        target < nums[mid] ? (r = mid) : (l = mid + 1);
    }
    return l - 1;
};
console.log(findLastIndex([1, 3, 3, 3, 3, 5], 3));