2020春招总结,已收到阿里意向书

2020春招总结,已收到阿里意向书

    • 面试情况
    • 面试记录
      • 阿里巴巴
        • 一面、二面(50min)
        • 三面、四面(50min)
        • HR面(30min)
      • 字节跳动
        • 一面、二面 (1h)
        • HR面(15min)
      • 美团
        • 一面 (70min)
        • 二面(50min)
        • 三面 (50min)
        • HR面 (45min)
    • 面试总结

本人19年年末来到百度实习(已离职),作为第一份工作,带给我的收获蛮大的。几个月的实习生活让我了解到了公司的开发流程、代码规范、团队沟通的能力等等,在这里先感谢老东家。下面是春招总结:

面试情况

  • 阿里巴巴(淘系技术部) - 意向书
  • 字节跳动(懂车帝) - offer
  • 美团(到店餐饮) - HR面结束
  • 网易雷火 - 未开始流程
  • 快手 - 未开始流程

面试记录

阿里巴巴

阿里巴巴是通过师兄内推投递的,在系统开之前提前面了一轮,一共四轮技术面(含一轮交叉面)+ 一轮HR面。总的流程还算是比较快,一个月左右走完流程。内推的好处就是如果流程卡住,内推人可以帮忙催一催面试官尽早安排面试。

一面、二面(50min)

因为最开始没有做面试记录,凭靠记忆想到了下面几个题

  • promise的原理,catch之后能调用then方法吗?
    • 略,可以。
let promise = new Promise((resolve, reject) => {
    reject(1);
});

// catch与then方法相同,都会返回一个promise对象,存在显式返回和隐式返回两种情况
// 1.隐式返回:返回一个resolve值为undefined的promise
promise.catch(err => {
    console.log(err); // 1
}).then(resolve => {
    console.log(resolve); // undefined 
});

// 2.显式返回一个promise
promise.catch(err => {
    return new Promise(resolve => {
        console.log(err); // 1
        resolve(2);
    })
}).then(resolve => {
    console.log(resolve); // 2
});
  • cookie有哪些属性?知道SameSite吗?
    • Domain、Path、Max-Age、Secure、HttpOnly
    • SameSite:把三个值Strict、Lax、None的作用讲一下,chrome80版本把默认值None改为Lax造成什么影响。推荐阮一峰老师的文章:Cookie 的 SameSite 属性
  • 浏览器事件循环和Node事件循环的区别
    • node11以下版本与浏览器事件循环的区别
  • 讲一下React新生命周期(16.3之后版本)
    • 旧版生命周期
      2020春招总结,已收到阿里意向书_第1张图片
    • 新版生命周期
      2020春招总结,已收到阿里意向书_第2张图片
    • 废弃了componentWillMount、componentWillReceiveProps、componentWillUpdate。React17将推出新的异步渲染方式,dom挂载之前将可以被打断,因此上述三个生命周期不能保证在需要执行的时候只执行一次
    • 新增getDerivedStateFromProps、getSnapshotBeforeUpdat
  • 优化首屏加载,讲一下代码分割
    • 使用suspense配合lazy封装动态引入模块组件
const myComponent = lazy(
    () => import(
        /* webpackChunkName: "index" */
        './index'
    );
);
 
const myAsyncComponent = props => (
  <Suspense fallback={<Loading />}>
    <myComponent {...props} />
  </Suspense>
);
  • 讲一下React错误边界
    • 错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。 ——react16开发文档
class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    static getDerivedStateFromError() {
        return { hasError: true };
    }

    render() {
        // 如果捕捉到子组件错误,渲染回退页ErrorComponent
        if (this.state.hasError) {
            return <ErrorComponent />;
        }
        
        // 如果未捕捉到子组件错误,渲染子组件
        return this.props.children;
    }
}

// 用法
<ErrorBoundary>
  <Child1 />
  <Child2 />
  ...
</ErrorBoundary>
  • 项目中有一个场景如何实现的(点击地图上一个县,找到所在的省、市)
// 数据结构如下,点击一个地址获取到该地址的id,通过广度遍历去找到它所在的路径
const data = [{
    id: '1',
    name: '四川省',
    children: [
        {
            id: '2',
            name: '阿坝藏族自治州',
            children: [
                {
                    id: '3',
                    name: '汶川县'
                }
            ]

        }
    ]
}];

// 当时考虑到提高点击一级、二级地点(省、市)的遍历速度。实际在这里两种遍历差别不大。
function bfs(target, id) {
    const stack = [...target];
    while (stack.length) {
        const current = stack.shift(); // 深度遍历的话换成pop
        if (!current.path) {
            current.path = new Array(current.id);
        }
        if (current.children) {
            stack.push(...current.children.map(
                item => {
                    return {
                        ...item,
                        path: current.path.concat(new Array(item.id))
                    }
                }
            ));
        }
        if (current.id === id) {
            return current.path;
        }
    }
    return undefined;
}
console.log(bfs(data, '3')); // [ '1', '2', '3' ]

三面、四面(50min)

三面四面都是围绕着个人项目和实习项目去问的,参考意义不大。到三面其实就是boss面了,主要看参加过的比赛和项目,如果参加过含金量比较高的比赛或者做过几个完整的项目(即使是一个完整的项目也比多个零散的拼凑项目强)会比较占优势。

HR面(30min)

HR在一个晚上突然打电话过来,直接进行了面试。问了专业相关的知识、如何学习前端、微信小程序设计大赛的收获、自己的优点、手里的offer(当时手里有个字节offer,就问了优先选择哪个,为什么)。面下来很快,大概半小时就结束了,没有感觉到HR很凶(网传阿里HR比较凶)。

字节跳动

周日上午一面,结束后面试官打电话约下午二面,晚上又接到电话约了HR面,整体流程非常快。

一面、二面 (1h)

  • 左侧200px,右侧自适应,两列等高(高不写死)
<div class="container">
    <div class="left">
        111
    div>
    <div class="right">
        11111<br/>
        11111
    div>
div>


.container {
    display: flex;
}
.left {
    width: 200px;
    background-color: blue;
}
.right {
    flex: 1;
    background-color: red;
}


.container {
    position: relative;
    width: 100%;
}
.left {
    position: absolute;
    width: 200px;
    height: 100%;
    background-color: blue;
}
.right {
    width: calc(100% - 200px);
    margin-left: 200px;
    background-color: red;
}


.container {
    display: table;
    width: 100%;
}
.left {
    display:table-cell;
    width: 200px;
    background-color: blue;
}
.right {
    display:table-cell;
    width: calc(100% - 200px);
    background-color: red;
}
  • 实现一个秒针动画
    • 可以用animation去做
  • span {padding: 12px 24px;},span标签上下左右内边距是多少
    • 上下:0、左右:24px
    • IFC相关
  • 怎么获取元素距离页面左上角距离top、left
    • offsetTop、offsetLeft
  • [] == false、{} == false
    • ==隐式转化
    • ([]).toString() = “”(空字符串)
    • ({}).toString() = “[object Object]”
    • Object.prototype.toString.call(),判断引用数据类型
  • 页面渲染流程,重绘、重排
  • [1, ‘2’, [3, 4]]转化为[1, ‘2’, 3, 4]
// 如果数组里全是字符串,可以用下面这个方法,在这里显然不行
arr.toString().split(',');

// 1 遍历
function bfs(arr) {
    let arr2 = [];
    let stark = [...arr];
    while(stark.length) {
        let item = stark.shift();
        item instanceof Array ? stark.push(...item) : arr2.push(item);
    }
    return [...new Set(arr2)];
}
console.log(bfs(arr));

// 2 递归
function foo(arr, result = []) {
    if (!(arr instanceof Array)) {
        result.push(arr);
        return;
    }
    arr.forEach(item => {
        foo(item, result);
    });
    return result;
}
console.log(foo(arr));
  • 自定义Hooks,useInView(页面隐藏再显示执行方法)
const useInView = function(fn) {
    useEffect(() => {
        const innerFn = function() {
            !document.hidden && fn();
        }
        // 绑定事件
        document.addEventListener('visibilitychange', innerFn);
        return (() => {
            // 卸载时注销事件
            document.removeEventListener('visibilitychange', innerFn);
        });
    });
}

function MyComponent() {
    useInView(() => {
        console.log(1111);
    });
    
    useInView(() => {
        console.log(2222);
    });
    
    return (
        <div></div>
    );
}
  • 找到第一个不重复字符,如 ‘abadc’ -> ‘b’,‘stEDeSS’ -> ‘t’,无不重复时返回空字符
  • 实现promise.all
  • react实现一个modal组件,支持打开和关闭功能,且modal内部的内容可以自定义
    • 使用hooks配合props.children
  • 给定有序数组array和数字n,找出n在array中起始位置的下标和终止位置的下标。如 array = [1, 1, 2, 2, 3], n = 2; 返回[2, 3]
    • 可以把n出现的下标放到数组里,返回第一项和最后一项,显然不是面试官想要的答案,面试官想让用LRU实现
  • 浏览器跨域的解决方法,cookie、localstorage、sessionstorage能否跨域,cookie如果超过存储上限会怎样
  • 下面代码输出
async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(function () {
  console.log('setTimeout');
}, 0);

async1();

new Promise(function (resolve) {
  console.log('promise1');
  resolve();
}).then(function () {
  console.log('promise2');
});

console.log('script end');

/**
 * script start
 * async1 start
 * async2
 * promise1
 * script end
 * promise2
 * async1 end
 * setTimeout
 */
  • 下面代码在Node环境下和浏览器环境下输出
console.log('start');
setTimeout(() => {
    console.log('children2');
    Promise.resolve().then(() => {console.log('children2-1')});
}, 0);
setTimeout(() => {
    console.log('children3')
    Promise.resolve().then(() => {console.log('children3-1')});
}, 0);
Promise.resolve().then(() => {console.log('children1')});
console.log('end');

// node11以下
/**
 * start
 * end
 * children1
 * children2
 * children3
 * children2-1
 * children3-1
 */

// 浏览器及node11以上
/**
 * start
 * end
 * children1
 * children2
 * children2-1
 * children3
 * children3-1
 */
  • 实现一个new方法
function _new(obj, ...args) {
    let newObj = {};
    newObj.__proto__ = obj.prototype;
    let ret = obj.call(newObj, ...args);
    return typeof ret === 'object' ? ret : newObj;
}

HR面(15min)

纯聊天,结束后没有口头offer,上午面完的,下午HR加微信说面试通过,次日中午收到offer邮件。字节跳动的面试效率可以说是非常高了。

美团

美团基本上隔两天约一轮面试,三轮技术+一轮HR。

一面 (70min)

  • 数据库中的死锁
  • 数据库中的范式
  • 操作系统进程的状态
    • 执行、阻塞、就绪
  • 自定义hooks实现componentDidUpdate(初始化时不执行)
const useMyDidUpdate = function(fn) {
    const status = useRef(false);
    useEffect(() => {
        // 初始化时不执行
        if (!status.current) {
            status.current = true;
            return;
        }
        fn();
    });
}
  • https的传输过程
    • 通过非对称加密传送对称加密的密钥
    • 拿到密钥后通过对称加密进行数据交换
    • CA证书防止中间人攻击。
    • 推荐微信开放社区的一篇文章一次安全可靠的通信——HTTPS原理
  • 实现垂直居中
<div class="container">
    <div class="item">div>
div>


.container {
    display: flex;
    justify-content: center;
    align-items: center;
}
.item {
    
}

.container {
    display: flex;
}
.item {
    margin:auto;
}


.container {
    position: relative;
}
.item {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}


.container {
    display: grid;
}
.item {
    justify-self: center;
    align-self: center;
}


.container {
    display: table;
}
.item {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
}

二面(50min)

  • git相关
    • git rebase 和 git merge的区别
    • git回滚到任意版本
  • map和weakMap的区别
    • 从能否遍历和成员是否弱引用的角度去答
  • 实现一个抽奖功能
    • 参与者放到数组里,生成一个随机的索引(概率相等),获取对应值
    • Math.random()左闭右开集合,概率不相等
    • Math.floor(Math.random()*(max-min+1)+min)在[min, max]概率相等
  • 实现发布订阅模式
let event = {
    // 存放订阅事件
    childrenList: {},

    // 订阅函数
    listen(type, fn) {
        //如果chilidrenlist里这个缓存不存在,就先将它创建为空,为后续做准备
        !this.childrenList[type] && (this.childrenList[type] = []);
        // 判断传进来的是否是一个函数,若是就加到childrenList[type]下的数组中等待执行
        typeof fn == 'function' && this.childrenList[type].push(fn);
        // console.log(this.childrenList)
    },

    // 发布函数
    touch(type) {
        let fns = this.childrenList[type];
        if (!fns && fns === 0) {
            return false
        }
        fns.forEach(fn => {
            fn.apply(this, [arguments]);
        });
    }
}

/**
 * 创建一个订阅小红
 */
event.listen('小红', arguments => {
    console.log(`${arguments[0]}${arguments[1]}`)
});
event.listen('小红', arguments => {
    console.log(`大家注意,我们班的${arguments[0]}${arguments[1]}`)
});
/**
 * 创建一个订阅小明
 */
event.listen('小明', arguments => {
    console.log(`${arguments[0]}${arguments[1]}`)
});
/**
 * 向小红订阅事件发布消息
 */
event.touch('小红', '这次考试英语成绩年纪第一');
/**
 * 向小明订阅事件发布消息
 */
event.touch('小明', '小明不出你的意料,你数学成绩还是倒数第一');
  • 实现快排
let arrA = [10, 11, 12, 13, 9, 8, 7,14];

function quickSort(arr) {
    // 递归的终止条件
    if (arr.length <= 1) {
        return arr;
    }
    let begin = arr[0];
    // 左指针
    let i = 1;
    // 右指针
    let j = arr.length - 1;
    while (i < j) {
        while (arr[i] < begin && i < j) {
            i ++;
        }
        while (arr[j] > begin && i < j) {
            j --;
        }
        // 交换两个数的位置
        let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    let left, right;
    if(arr[i] < begin){
        left = arr.slice(1, i+1) ;
        right = arr.slice(i+1, arr.length);
    }
    if(arr[i] >= begin){
        left = arr.slice(1, i) ;
        right = arr.slice(i, arr.length);
    }
    return [...quickSort(left), begin, ...quickSort(right)];
}

console.log(quickSort(arrA));

三面 (50min)

  • 前端工程化
  • 发布订阅模式和观察者模式的区别
  • 项目相关

HR面 (45min)

和上面两轮HR面一样,就是聊聊天。

面试总结

以上就是本人春招面试的记录,由于流程比较长,上面这些都是印象比较深的题目。感觉阿里的面试会稍微难一些,问的会比较有深度。字节跳动和美团偏向于代码能力,这两个全程都是用牛客面试,美团一面的时候还侧重考察了专业课水平。希望大家都可以早日拿到满意的offer。

你可能感兴趣的:(前端)