Shopee前端面试

1,796 阅读1分钟

这个并不是我参与的面试,是朋友参加的一个面试,所以不会有较多的面试细节和面试感受,更多的是对面试题的解析。

一面

面试题1: 说出下面的打印顺序和结果

console.log('begin');
for(var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
console.log('end');

输出结果是: begin end 5 5 5 5 5
解析:setTimeout是宏任务,肯定是在最后上面代码中最后执行的,在执行回调函数的时候,i的值已经是5了,且5个5是同时输出的

在这个时候肯定会被追问
怎么修改才能让这段代码输出 0 1 2 3 4

1. 立即执行函数

for(var i = 0; i < 5; i++) {
    (function(params) {
        setTimeout(function() {
            console.log(params);
        }, 1000);
    })(i)
}

2.利用setTimeout的第三个参数

for(var i = 0; i < 5; i++) {
    setTimeout(function(params) {
        console.log(params);
    }, 1000, i);
}

3. 利用Es6的let

for(let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000)
}

面试题2:代码执行

var a = 1;
function Fn1() {
    var a = 2;
    alert(this.a + a); // 这儿会执行几次,分别是多少
}
function Fn2() {
    var a = 10;
    Fn1(); // 3
}
Fn2();
var Fn3 = function() {
    this.a = 3;
}
Fn3.prototype = {
    a: 4
}
var fn3 = new Fn3();
Fn1.call(fn3); // 5

结果:alert会执行2两次,结果分别是 3 5; 解析:

  • 第一次执行的时候是在Fn2函数中被调用,此时 Fn1中的this指向全局,所以 答案为 1 + 2 = 3
  • 第二次执行是上上面的最后一样,fn3对象的a属性的值是3,因为使用了call函数,所以Fn2中的this指向fn3,所以结果是3 + 2 = 5

考点:

  1. 作用域在函数声明的时候就决定了,所以 alert 中的第二个a的值一直是 2
  2. 原型和原型链,new函数的执行
  3. call、apply、bind

面试题4: 自定义数组方法

给数组原型上添加一个方法返回数组的深度 测试示例:

[].getDepth(); // 1
[1, 2, 3].getDepth(); // 1
[1, 2, [3, 4]].getDepeth(); // 2
[1, 2, [3, 4],[6, [7, 8]]].getDepeth(); // 3

答案:

 Array.prototype.getDepth = function() {
    if(!Array.isArray(this)) {
        throw new Error(`typeof ${this} is Error`);
    }
    const maxDepth = (arr) => {
        const dep = [1];
        for(let i = 0; i < arr.length; i++) {
            if(Array.isArray(arr[i])) {
                dep.push(maxDepth(arr[i]));
            }
            else {
                dep.push(1);
            }
        }
        return Math.max(...dep) + 1;
    }
    return maxDepth(this) - 1;
};

面试题4: 算法

假设100人,分编号1~100,从1号开始报数,报数到3号时,3号淘汰,然后有下一任从1报数,以此类推,最后谁会活下来?
比如100报的是1,再从第一个报2,最后只剩一个编号 方法一

let start = 0;
let i = 0;
while(arr.length > 1) {
    if(start === 3) {
        arr.splice(i, 1);
        start = 1;
    }
    else {
        i++;
        start++;
    }
    if(i >= arr.length) {
        i = 0;
    }
}

方法二

let arr = [...new Array(100).keys()];
let start = 0;
while(arr.length > 1) {
    if(start === 3) {
        arr.shift();
        start = 1;
    }
    else {
        arr.push(arr.shift());
        start++;
    }
}

二面

1、自我介绍

2、自己觉得比较有挑战的和有成就的项目

3、算法题一

有两个请求,按照优先有序打印顺序打印; 例如: req1: 10ms、req2: 5ms; 10ms后打印出 req1、req2的结果 req1: 5ms、req2: 10ms; 5ms后打印出req1、再过5ms后打印出req2

function req(time) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(time);
        }, time);
    });
}
function sequence(reqs) {
    let res = [];
    let resIndex = 0;

    for(let i = 0, l = reqs.length;  i < l ; i++){
        let time = reqs[i];
        req(time).then(r => {
            res[i] = r;
            getRes(i);
        });
    }
    function getRes(index) {
        if(index === resIndex && res.hasOwnProperty(index)) {
            console.log(res[index]);
            resIndex++;
            getRes(resIndex);
        }
    }
}

4. 算法二 数组[1,2,3]的全排列方法

function rank (arr) {
    let len = arr.length;
    let res = [];
    function getArr(left, curItem) {
        if(left.length === 0) {
            res.push(curItem);
            console.log(curItem);
            return;
        }
        for(let i = 0, l = left.length; i < l; i++) {
            const item = left[i];
            const next = [...curItem];
            next.push(item);
            const newLeft = [...left];
            newLeft.splice(i, 1);
            getArr(newLeft, next);
        }
    }
    getArr(arr, []);
    return res;
}

5、你有什么需要了解的问题?

答题技巧:首先要问的是技术栈,其次要问团队小组规模,最后问下我如果有幸入职负责哪个方向的业务(可问可不问);其次是看个人发挥,跟技术官最好没必要问福利方面的; 欢迎大佬们点赞推上热门