# Interviews

# 0. 日程

# 0.1 节点日期

日期 时间 内容
2020.08.17 14:00 - 15:00 字节跳动(一面)
2020.08.18 19:00 - 20:15 BIGO(笔试)
2020.08.19 14:00 - 15:00 字节跳动(二面)
2020.08.20 18:00 - 19:00 美团(一面)
2020.08.21 19:00 - 20:40 滴滴(笔试)
2020.08.22 19:00 - 20:30 猿辅导(笔试)
2020.08.25 11:00 - 12:00 美团(二面)
2020.08.26 14:30 - 16:30 Shopee(笔试)
2020.08.27 19:00 - 21:00 京东(笔试)
2020.08.28 15:00 - 16:00 京东(一面)
2020.08.29 10:00 - 11:30 斗鱼(笔试)
2020.08.29 14:00 - 15:00 猿辅导(一面)
2020.08.29 19:00 - 20:30 OPPO(笔试)
2020.08.31 11:30 - 12:30 Shopee(一面)
2020.09.01 19:00 - 20:30 拼多多(笔试)
2020.09.02 10:30 - 11:30 京东(一面)
2020.09.03 19:00 - 21:00 百度(笔试)
2020.09.04 11:30 - 12:30 腾讯(一面)
2020.09.04 14:00 - 15:00 猿辅导(二面)
2020.09.04 15:30 - 16:30 Shopee(二面)
2020.09.05 16:00 - 17:00 快手(一面)
2020.09.06 10:00 - 12:00 字节跳动(笔试)
2020.09.06 19:00 - 21:00 华为(笔试)
2020.09.06 19:00 - 20:00 小红书(笔试)
2020.09.06 20:00 - 22:00 腾讯(笔试)
2020.09.08 18:00 - 19:30 小米(笔试)
2020.09.08 19:00 - 21:00 携程(笔试)
2020.09.09 10:20 - 11:20 OPPO(一面)
2020.09.10 14:00 - 15:00 滴滴(一面)
2020.09.10 15:30 - 15:50 美团(HR面)
2020.09.10 16:00 - 17:00 滴滴(二面)
2020.09.10 17:00 - 18:00 滴滴(三面)
2020.09.12 14:00 - 15:00 猿辅导(三面)
2020.09.12 15:00 - 17:00 网易(笔试)
2020.09.13 14:00 - 15:00 百度(一面)
2020.09.13 15:00 - 16:00 百度(二面)
2020.09.13 16:00 - 17:00 百度(三面)
2020.09.14 14:00 - 15:00 小米(一面)
2020.09.14 16:00 - 17:00 快手(二面)
2020.09.14 18:00 - 19:00 爱奇艺(一面)
2020.09.15 11:30 - 12:30 Shopee(HR面)
2020.09.15 16:40 - 17:40 OPPO(二面)
2020.09.17 16:00 - 17:00 字节跳动(一面)
2020.09.18 15:00 - 16:00 字节跳动(二面)
2020.09.19 09:30 - 10:30 OPPO(HR面)
2020.09.19 11:00 - 12:00 爱奇艺(二面)
2020.09.22 15:00 - 16:00 字节跳动(三面)
2020.09.24 15:00 - 16:00 爱奇艺(三面)

# 0.2 当前状态

日期 企业 状态
2020.09.10 美团 HR面(未知
2020.09.10 滴滴 三面(良好
2020.09.14 快手 二面(普通
2020.09.18 Shopee 意向书(完结
2020.09.18 猿辅导 意向书(完结
2020.09.22 百度 意向书(完结
2020.09.27 字节跳动 意向书(完结
2020.09.29 OPPO offer排序(泡池子
2020.09.30 爱奇艺 意向书(并没有

# 0.3 企业情况

# 0.3.1 Shopee

  • 地点:深圳
  • 新员工培训:2~3周上岗接手业务
  • 上班时间:9:30 - 19:00,午休1.5h,双休。
  • 期望薪资:23*15

# 0.3.2 猿辅导

  • 地点:北京
  • 新员工培训:1个月的脱产培训,授课的模式,一对一的导师
  • 上班时间:10:00 - 19:00,午休2h,双休。
  • 部门:双向选择,可申请调换。
  • 十月中旬发放offer,并且近期会有一个业务的沟通。

# 0.3.3 OPPO

  • 地点:成都
  • 新员工培训:六个月的脱产培训,深圳/东莞
  • 上班时间:21:00 - 22:00下班
  • 期望薪资:26w

# 1. 字节跳动

# 2020.08.17 - 一面(50分钟)

  1. 一分钟自我介绍

  2. 为什么想要学前端呢?

  3. axios 写一个比较通用的 ajax 请求函数 (我不熟悉 axios,原生写的)

    const axios = require('axios');
    
    function request(url, method, data) {
      if (method.toLowerCase() === 'get') {
        url += '?';
        for (let key in data) {
          url += `${key}=${data[key]}&`;
        }
        url = url.slice(0, url.length - 1);
    
        return axios({
          method: method,
          url: url
        });
      } else {
        return axios({
          method: method,
          url: url,
          data: data
        });
      }
    }
    
  4. 判断数据类型的函数

    function f(param) {
      if (param === null) return 'null';
      if (typeof param === 'object') {
        if (param.__proto__ === Array.prototype) return 'Array';
        if (param.__proto__ === Set.prototype) return 'Set';
      }
      return typeof param;
    }
    
  5. 闭包的含义、应用场景、优化

    // 手动回收闭包中的变量
    function closure(name) {
      let self = this;
      self.name = name;
      return function() {
           console.log(self.name);
           delete self.name;
      }
    }
    
  6. 函数的私有变量和oop中的区别?

    好吧我试了试,感觉都是可以继承,但不能直接访问,只能调用父类中的方法去访问,这个方法也是可以继承的。其他的我也不知道有什么区别。

  7. 什么是原型链?有什么作用呢?

  8. CSS定位方式有哪些?

    static、relative、absolute、fixed

    sticky:

    • 需要搭配 top/bottom/left/right,效果类似于 relative + fixed的结合

    • 到达阈值之前,是 relative,之后是 fixed。eg. 图片堆叠效果

  9. 垂直居中

  10. 盒子模型,怪异盒子模型我不会(好吧我查了一下,就是IE盒子模型)

  11. 写一个深拷贝

    /*
    深拷贝
    为什么没有对函数做特判?
    1.函数的拷贝本身没有什么应用场景
    2.lodash里面对函数的处理也是直接返回,没有特殊处理
    3.非要做的话,prototype来区分普通函数和箭头函数:
      3.1 用 eval + func.toString() 的思路来拷贝箭头函数
      3.2 普通函数... 口胡一下吧
    */
    function deepClone(obj) {
      if (obj === null) return obj;
      if (obj instanceof Date) return new Date(obj);
      if (obj instanceof RegExp) return new RegExp(obj);
      if (typeof obj !== "object") return obj;
      let cloneObj = new obj.constructor();
      for (let key in obj) {
        if(obj.hasOwnProperty(key)){
          cloneObj[key] = deepClone(obj[key]);
        }
      }
      return cloneObj;
    }
    
    // 浅拷贝
    function shallowClone(obj) {
      let cloneObj = {};
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          cloneObj[key] = obj[key];
        }
      }
      return cloneObj
    }
    
  12. JavaScript有哪些数据类型?

  13. 实现数组扁平化函数

    • 输入:[1,2,[3, [4,5,[6]],7]]

    • 输出:[1,2,3,4,5,6,7]

    • function recur(array) {
          for (let i = 0; i < array.length; i++) {
              if (typeof array[i] === 'object') {
                  recur(array[i]);
              } else {
                  ans.push(array[i]);
              }
          }
      }
      
  14. TCP、UDP的区别

  15. TCP怎么保证可靠数据传输?(流量控制和拥塞控制)

  16. TCP首部太大了怎么解决?(HTTP 2.0 有首部压缩,其他我不知道)

  17. HTTP / TCP 队头阻塞

# 2020.08.19 - 二面(70分钟)

  1. 看你之前都是python、神经网络,为什么想到要学前端?

  2. 对于前端的认识?学习的方法?

  3. 介绍一下项目?

    1. 项目怎么性能优化的?
    2. FastClick解决的什么问题?底层的原理?
      • 解决的问题:早些年的浏览器,为了监听双击事件用以缩放,在touchendclick触发之间设置了一个300ms左右的等待。
      • 原理:
        • 移动端,当用户点击屏幕时,会依次触发: touchstart => touchmove(0 次或多次) => touchend => mousemove => mousedown => mouseup => click => touchmove
        • 只有当手指在屏幕发生移动的时候才会触发 touchmove 事件。在 touchstarttouchmove 或者 touchend 事件中的任意一个调用 event.preventDefaultmouse 事件 以及 click 事件将不会触发。
        • fastClick 在 touchend 阶段 调用 event.preventDefault,然后通过 document.createEvent 创建一个 MouseEvents,然后 通过 eventTarget.dispatchEvent 触发对应目标元素上绑定的 click 事件。
      • 谨慎使用:2015年后的移动端浏览器,尤其是Chrome和Safari,不再有300ms的touch延迟,因此继续使用fastClick不仅没什么作用,反而会引入一些隐含的bug/风险。
    3. 为什么用BetterScroll
      • 最开始是 iscroll,解决的问题:
        • 移动端滑动卡顿,缺少边缘回弹、惯性滑动等功能
        • 添加自定义事件(不确定)
        • 早些年不支持页面的局部滚动(不确定)
    4. 移动端的吗?怎么做响应式布局?
    5. 怎么从手稿到布局设计的?
    6. 最大的收获?
  4. VueRouter的History和Hash模式,它们各自监听了什么事件?

    • History:html5的history API,history.pushState() 和 history.repalceState()函数,popstate事件来监听url的变化
    • Hash:location.hash,hashchange事件
  5. 盒模型?

    • box-sizing
    • content-box w3c标准盒模型
    • border-box IE盒模型
  6. 三列布局?

  7. 事件的触发,应该是问的事件循环机制

  8. 箭头函数和普通函数的区别?

    • 箭头函数没有自己的this,它只会从自己的作用域链的上一层继承this
    • 箭头函数继承来的this不会动态改变
    • .call()/.apply()/.bind()无法改变箭头函数中this的指向
    • 箭头函数不能作为构造函数使用
    • 箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。
    • 箭头函数没有原型prototype,但是可以通过__proto__访问到他的构造器(Function)的prototype,即Function.prototype
  9. apply、call、bind的作用?bind中arguments的作用?

    bind中的argument会绑定给返回的新函数,也就是说,在调用新函数的时候,这些参数会被放在前面,并将传入的参数(如果有)追加在后面,然后进行函数调用。

  10. HTTP有哪些请求方法?

    方法 描述
    GET GET请求会显式请求指定的资源。一般来说GET方法应该只用于数据的读取,而不应当用于会产生副作用的非幂等的操作中。它期望的应该是而且应该是安全的和幂等的。这里的安全指的是,请求不会影响到资源的状态。
    POST POST请求会向指定资源提交数据,请求服务器进行处理,如:表单数据提交、文件上传等,请求数据会被包含在请求体中。POST方法是非幂等的方法,因为这个请求可能会创建新的资源或/和修改现有资源。
    PUT PUT请求会向指定资源位置上传其最新内容,PUT方法是幂等的方法。通过该方法客户端可以将指定资源的最新数据传送给服务器取代指定的资源的内容。
    DELETE DELETE请求用于请求服务器删除所请求的URI(统一资源标识符,Uniform Resource Identifier)所标识的资源。DELETE请求后指定资源会被删除,DELETE方法也是幂等的。
    HEAD HEAD方法与GET方法一样,都是向服务器发出指定资源的请求。但是,服务器在响应HEAD请求时不会回传资源的内容部分,即:响应主体。这样,我们可以不传输全部内容的情况下,就可以获取服务器的响应头信息。HEAD方法常被用于客户端查看服务器的性能。
    OPTIONS OPTIONS请求与HEAD类似,一般也是用于客户端查看服务器的性能。 这个方法会请求服务器返回该资源所支持的所有HTTP请求方法,该方法会用'*'来代替资源名称,向服务器发送OPTIONS请求,可以测试服务器功能是否正常。JavaScript的XMLHttpRequest对象进行CORS跨域资源共享时,就是使用OPTIONS方法发送嗅探请求,以判断是否有对指定资源的访问权限。
    TRACE TRACE请求服务器回显其收到的请求信息,该方法主要用于HTTP请求的测试或诊断。
    PATCH PATCH方法出现的较晚,它在2010年的RFC 5789标准中被定义。PATCH请求与PUT请求类似,同样用于资源的更新。二者有以下两点不同:1.PATCH一般用于资源的部分更新,而PUT一般用于资源的整体更新。2.当资源不存在时,PATCH会创建一个新的资源,而PUT只会对已存在的资源进行更新
    CONNECT CONNECT方法是HTTP/1.1协议预留的,能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接与非加密的HTTP代理服务器的通信。
  11. 状态码 301 / 302?

    • 301 Moved Permanently:被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。

    • 302 Moved Temporarily:请求的资源现在临时从不同的URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。

      301比较常用的场景是使用域名跳转。302用来做临时跳转 比如未登陆的用户访问用户中心重定向到登录页面。

  12. 4系的状态码和5系的状态码有什么区别?

    • 1系:这类响应是临时响应,代表请求已被接受,需要继续处理。
    • 2系:代表请求已成功被服务器接收、理解、并接受。
    • 3系:代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。
    • 4系:代表了客户端看起来可能发生了错误,妨碍了服务器的处理。
    • 5系:代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。
  13. cache-control中的 max-age

  14. // 代码题一
    
    首次访问后,在第35秒第2次访问,在第65秒第3次访问,请问2次访问,第3次访问 Status Code 分别为什么?
    
    Request Header
    Cache-Control: max-age=60
    If-Modified-Since: Fri, 12 Jun 2020 06:35:37 GMT
    If-None-Match: W/"5ee32239-c9b"
    
    Response Header
    Cache-Control: max-age=60
    ETag: W/"5ee32239-c9b"
    Last-Modified: Fri, 12 Jun 2020 06:35:37 GMT
    
  15. // 代码题二
    
    /*
    期间冒泡排序的时间复杂度
    查找一个数组的第二大的数,要求时间复杂度为O(n),如果没有就返回最大数字。
    */
    
    function heapify() {}
    
    let array = [5, 5, 5, 5];
    
    function solution(nums) {
        let big1 = -Infinity, big2 = -Infinity;
        for (let i = 0; i < nums.length; i++) {
            if (nums[i] === big1 || nums[i] === big2) continue;
            if (nums[i] > big1 && big2 !== -Infinity) {
                big1 = nums[i];
                if (big1 < big2) {
                  [big1, big2] = [big2, big1];
                }
            } else if (nums[i] > big2) {
                big2 = nums[i];
            }
        }
        if (big2 === -Infinity) return big1;
        return big2;
    }
    
  16. // 代码题三
    
    /*
    Semantic Versioning 是一个前端通用的版本规范。格式为“{MAJOR}.{MINOR}.{PATCH}-{alpha|beta|rc}.{number}”,要求实现 compare(a, b) 方法,比较 a, b 两个版本大小
    
    1. 当 a > b 是返回 1;
    2. 当 a = b 是返回 0;
    3. 当 a < b 是返回 -1;
    4. 其中,rc > beta > alpha,
    5. 例子,1.2.3 < 1.2.4 < 1.3.0.alpha.1 < 1.3.0.alpha.2 < 1.3.0.beta.1 < 1.3.0.rc.1 < 1.3.0
    */
    
    let testCases = [['1.2.3', '1.2.4'], 
                     ['1.2.4', '1.2.4'], 
                     ['1.2.4', '1.2.4.alpha'],
                     ['1.2.3.alpha', '1.2.3.beta']];
    
    function compare(edition1, edition2) {
        if (edition1 === edition2) return 0;
        
        let e1 = edition1.split('.');
        let e2 = edition2.split('.');
        
        let i;
        for (i = 0; i < Math.min(e1.length, e2.length); i++) {
            if (e1[i] !== e2[i]) {
                if (e1[i].charCodeAt() > e2[i].charCodeAt()) {
                    return 1;
                } else {
                    return -1;
                }
            }
        }
        
        if (e1.length < e2.length) return 1;
        return -1;
    }
    
    testCases.forEach(testcase => console.log(compare(testcase[0], testcase[1])));
    

# 2. 美团点评

# 2020.08.19 - 一面(40分钟)

  1. 为什么想要学前端呢?

  2. 关于简历上的项目

    1. 为什么选用Vue呢?
    2. 项目是几个人?怎么分工的呢?
    3. 项目中哪里用到了v-if、v-bind等vue的操作的呢?
    4. 同源了解过吗?
    5. 项目中有遇到过跨域的问题吗?
    6. CORS了解过吗?
      • 简单请求
        1. 客户端请求头,带上一个Origin字段,表明自己的域名
        2. 如果服务器:
          1. 允许该域名内的网页请求跨域,则会返回一个响应,头部带有以下字段:
            • Access-Control-Allow-Origin:表示允许发送跨域请求的域名(也就是请求中的Origin),或者是*
            • Access-Control-Allow-Credentials:表示是否允许发送cookie
            • Access-Control-Expose-Headers:XHR对象想要得到的6个基本字段(Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma)以外的字段
          2. 不允许该域名内的网页跨域,则返回的响应头中没有以上的字段。
        3. 如果跨域请求还要发送cookie,则需要在AJAX请求中设置xhr.withCredentials=true属性,其他域名的cookie不会上传,并且(跨源)原网页代码中的document.cookie也无法读取到服务器域名下的cookie
      • 非简单请求:对服务器有特殊要求的请求,比如请求方法为PUTDELETE、或者Content-Type字段的类型是application/json
        1. 预检的请求:先询问服务器:
          • 当前网页是否在允许跨域请求的域名名单中(白名单)
          • 有哪些可用的HTTP方法和头部字段
          • 预检的请求使用OPTIONS方法,头部中的关键字段是Origin,表示来自哪个源,此外还有两个字段:
            • Access-Control-Request-Method:列出客户端的CORS请求会用到哪些HTTP方法
            • Access-Control-Request-Headers:指定客户端CORS请求会额外发送的头部信息字段
        2. 如果服务器:
          1. 允许跨域,则会响应头中带有以下字段:
            • Access-Control-Allow-Origin
            • Access-Control-Allow-Methods
            • Access-Control-Allow-Headers
            • Access-Control-Allow-Credentials:true
            • Access-Control-Max-age:1728000,表示本次预检的有效期
          2. 不允许跨域,就没有以上的各种字段,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。
    7. 项目中cookie有使用吗?
    8. cookie的长度限制?
      • Firefox和Safari:4079字节
      • Opera:4096字节
      • IE:4095字节
      • 同时还会受到URL长度的限制
    9. Vue3 有了解吗?
    10. Vue3 的 vite 了解过吗?
  3. CSS的优先级?

  4. 事件循环机制?

  5. 函数的柯里化?(这个我真的不会了)

  6. function sayHi () {
      console.log(name);
      console.log(age);
      var name = '小明';
      const age = 6;
    }
    sayHi();
    
  7. let val = "name";
    console.log('val = ' + (val === 'name') ? 'something': 'nothing');
    
  8. <style>
    .text-color { color:green }
    .text-color { color: yellow }
    div.text-color { color: pink }
    div .text-color { color: blue }
    </style>
    
    <div id="red" class="text-color">color</div>
    
  9. function HaveResolvePromise(){
      return new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve(100)
            }, 0);
        })
      }
    async function getResult() {
      console.log(1)
      let a = await HaveResolvePromise()
      console.log(a)
      console.log(2)
    }
    console.log(0)
    getResult();
    console.log(3)
    
  10. // 函数的柯里化
    sum(2, 2, 3)(4, 5)(5).toValue() === 21
    
    function sum() {
      let args = [...arguments];
      let fn = function () {
        args.push(...arguments);
        return fn;
      };
      fn.toValue = function () {
        return args.reduce((x, y) => x + y);
      };
      return fn;
    }
    
    let ans = sum(2, 2, 3)(4, 5)(5);
    console.log(ans.toValue());
    
    // 什么是柯里化?将函数与传递给函数的参数结合在一起,产生出一个新的函数(有点工厂函数的意思?)
    Function.method('curry', function() {
      let args = arguments;
      let that = this;
      return function() {
        return that.apply(null, args.concat(arguments));
      };
    });
    

# 2020.08.25 - 二面(40分钟)

  1. 为什么学前端呢?

  2. 介绍下项目?

    1. 为什么用vue?
    2. 用到了哪些技术栈呢?
  3. 平时用Linux吗?

    1. 查看文件一般用的什么命令?(cat echo vim)
    2. 一个很大的文件,如果要在最后一行添加内容,vim怎么做呢?
    3. 登陆服务器用到了什么协议?
    4. ssh是什么层的协议?
    5. 拷贝文件用什么命令?
    6. 写一个scp吧
  4. HTTP有哪些请求方法?

  5. PUT和POST的区别?

    方面 POST PUT
    语义 提交,上传数据 更新数据
    幂等
    URI URI将处理包含在资源中的POST请求。该资源可能是一个数据接受进程、其他协议的网关,或者是接受注释的独立实体。 PUT请求中的URI标识请求中包含的实体,用户代理知道URI的意图,服务器不能尝试将请求应用于其他资源。
    例子 POST /device-management/devices : Create a new device PUT /device-management/devices/{id} : Update the device information identified by "id"
  6. restful下怎么写POST?

  7. CORS每次发送非简单请求,都需要预检吗?

  8. 图片的position 0在哪?那background-color的呢?

    • 好吧没懂,只想到了 background-position + CSS Sprites 定位来显示指定的部分,遮挡剩余的部分。
    • 没懂 bgc 哪来的position,可能是想问background-position?那(0, 0)应该就是左上角吧
  9. 有哪几种position?

  10. 写个布局,上下两行,第一行定高,宽度自适应;第二行两列,第一列定宽,高度自适应,第二列上下都撑满

    1. 第二行 float + calc

      <body>
        <div class="header"></div>
        <div class="aside"></div>
        <div class="container"></div>
      </body>
      
      html, body {
          height: 100%;
          margin: 0px;
          padding: 0px;
      }
      
      .header {
        height: 100px;
        background-color: #f80;
      }
      
      .aside {
        float: left;
        width: 100px;
        height: calc(100% - 100px);
        background-color: #f00;
      }
      
      .container {
        float: left;
        width: calc(100% - 100px);
        height: calc(100% - 100px);
        background-color: #0f0;
      }
      
    2. 第二行 absolute + bottom:0 + top

      <body>
        <div class="header"></div>
        <div class="row2">
          <div class="aside"></div>
          <div class="container"></div>
        </div>
      </body>
      
      body {
        padding: 0;
        margin: 0;
      }
      
      .header {
        height: 100px;
        background-color: #f80;
      }
      
      .row2 {
        position: absolute;
        top: 100px;
        bottom: 0;
        display: flex;
        width: 100%;
      }
      
      .aside {
        width: 200px;
        background-color: #ff0;
      }
      
      .container {
        flex-grow: 1;
        background-color: #0ff;
      }
      
    3. body用flex

      <body>
        <div class="header"></div>
        <div class="row2">
          <div class="aside"></div>
          <div class="container"></div>
        </div>
      </body>
      
      html, body {
        height: 100%;
      }
      
      body {
        padding: 0;
        margin: 0;
        display: flex;
        flex-direction: column;
      }
      
      .header {
        height: 100px;
        background-color: red;
      }
      
      .row2 {
        height: 100%;
        display: flex;
      }
      
      .aside {
        width: 100px;
        height: 100%;
        background-color: #f80;
      }
      
      .container {
        flex-grow: 1;
        background-color: #ff0;
      }
      
  11. 找出对象数组中,最大最小价格的差值,写个快排吧

# 3. 京东

# 2020.08.28 - 一面(40分钟)

  1. 深拷贝怎么实现呢?

    • 有以下几个注意点:
      • Date、RegExp不可遍历的,最开始instanceof判断他们是不是对应的实例,可以直接返回 new + 继承
      • symbol属于基本数据类型,可以直接返回。
      • 为什么不考虑函数的克隆?没有应用场景,而且lodash的源码中,深拷贝似乎也并没有考虑函数。lodash/baseClone.js的源码中就直接返回了函数
  2. 项目中怎么布局的呢?

  3. 提示框?动画的实现?

    • 项目中的loading菊花图就是用 伪元素 + animation + @keyframes{0% 35% 70% 100%} 来实现的
    • 概念:
      • animation(动画):用于设置动画属性,是一个简写的属性,包含6个属性
      • transition(过渡):用于设置元素的样式过度,和animation有着类似的效果,但细节上有很大的不同
      • transform(变形):用于元素进行旋转、缩放、移动或倾斜,和设置样式的动画并没有什么关系,就相当于color一样用来设置元素的“外表”
      • translate(移动):translate只是transform的一个属性值,即移动。
    • 详细:
      • transition:
        • 需要事件触发,所以没法在网页加载时自动发生
        • 是一次性的,不能重复发生,除非一再触发
        • 只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态
        • 一条transition规则,只能定义一个属性的变化,不能涉及多个属性。
      • animation:可以理解为,是由多个transition的效果叠加,并且可操作性更强,能够做出复杂酷炫的效果
    • 总结:
      • animation 动画~关键帧(@keyframes + %),往复性。
      • transition 过渡~ 属性,触发动作,一过性。
      • transform 变换~ 复杂的变换参数。
    • 参见:CSS动画
  4. 怎么实现返回顶部的按钮?动画的实现?

  5. localStorage?

    • 键值对总是以字符串的形式保存的
    • 打印出来看有点像 object 的形式,但是应该是属于 Storage 之类的类型。
    • window.localStorage
    • 方法:
      • localStorage.setItem('myCat', 'Tom');
      • let cat = localStorage.getItem('myCat');
      • localStorage.removeItem('myCat');
      • localStorage.clear();
  • sessionStorage:**在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,**这点和 session cookies 的运行方式不同。其他都一样。
  1. cookie?怎么读取cookie?

    • document.cookie,该字符串包含所有的Cookie,每条cookie以分号+空格「; 」分隔。(注意,这里每条cookie指的是一对键值对。)
    • 如果网页允许修改的话,可以直接操纵字符串即可
    • 读取的时候有两种方式:
      • split('; '),拆分为键值对,然后split('=')得到keyvalue
      • 如果是指定了key,则indexOf()先找到key的开始位置,加上key.length + 1,再设置indexOf()的第二个参数fromIndex来设置开始查找的位置,从这里开始找到结束的位置(即「;」)。
  2. 跨域?如果主域相同,子域不同,算不算跨域?同源策略 + 跨域方案?

  3. DNS?

  4. 输入url到一个网页显示的过程中发生了什么呢?

  5. 闭包的应用场景?

  6. 了解什么框架吗?

  7. 介绍下Vuex?

  8. 有哪些遍历数组的方法?

  9. 有哪些继承方法?最常用的?

  10. 重绘和回流?

  11. Jest?

  12. 哪些性能优化呢?

  13. TypeScript?

  14. 了解骨架屏的原理吗?

    • 方法一:
      • 创建与显示内容相似的html结构
      • 在需要显示内容的元素上增加背景色
    • 方法二:
      • 背景动画,html结构相同,修改部分css样式

# 4. 猿辅导

# 2020.08.29 - 一面(40分钟)

  1. 介绍一下项目

    1. 技术栈?
    2. 主要负责的部分?
    3. 怎么做的响应式布局?
    4. 介绍一下Vue Router?
    5. 做了哪些优化?
  2. 垃圾回收机制?

  3. 输入一个url到页面显示都有哪些?

    1. 强缓存 + 协商缓存
    2. DNS HTTP/HTTPS TCP/UDP
    3. DOM CSSOM RenderTree 分层合成 布局计算 光栅化 渲染层合成
  4. 写个原型链继承?

    function superType() {}
    function subType() {}
    
    subType.prototype = new superType();
    subType.prototype.constructor = subType;
    
  5. 判断一棵二叉树是否为满二叉树?(层序遍历)那怎么优化呢?(递归 + 求二叉树深度的思路,应该还可以剪枝)

    function solution(root) {
        if (!root) return true;
        let queue = [root];
        while (queue.length) {
            let nextQueue = [];
            let isEnd = false;
            if (!queue[0].left && !queue[0].right) {
                isEnd = true;
            }
            if (isEnd) {
                for (let i = 0; i < queue.length; i++) {
                    if (queue[i].left || queue[i].right) {
                        return false;
                    }
                }
                return true;
            } else {
                for (let i = 0; i < queue.length; i++) {
                    if (queue[i].left) nextQueue.push(queue[i].left);
                    if (queue[i].right) nextQueue.push(queue[i].right);
                }
                queue = nextQueue;
            }
        }
    }
    

# 5. Shopee

# 2020.08.31 - 一面(60分钟)

  1. 项目?

  2. 跨域怎么做的?devServer : proxy -> http-proxy-middleware -> 更低层的原理?

  3. CORS?

  4. 其他的跨域方式?

  5. jsonp的原理?

  6. 浏览器的事件机制?事件委托?

  7. HTTP的状态码?

  8. HTTP的缓存机制?(不是浏览器的缓存机制)

  9. 为什么要有缓存呢?

  10. domcontentloaded和load?

  11. 一个关于的this的题目讲console.log出的是什么,考察了箭头函数的this,现在看不到题目了,但比较简单。

  12. 手写函数判断 isArray?ES6怎么做?(Array.isArray()

  13. 了解观察者订阅者模式吗?手写一个类,实现观察者-订阅者模式?

    class pubSub {
      constructor() {
        // this.subscribers = [];
        this.topics = new Map();
      }
    
      publish(topic, data) {
        let subscribers = this.topics.get(topic);
        subscribers.forEach(subscriber => {
          subscriber.notify(data);
        })
      }
    
      subscribe(topic, subscriber) {
        if (!this.topics.has(topic)) {
          this.topics.set(topic, []);
        }
        
        let subSequence = this.topics.get(topic);
        subSequence.push(...subscriber);
      }
    
      unSubscribe(topic, subscribers) {
        let subSequence = this.topics.get(topic);
        subscribers.forEach(subscriber => {
          let index = subSequence.indexOf(subscriber);
          subSequence.splice(index, 1);
        })
      }
    }
    
  14. promise实现一个sleep(seconds)阻塞的函数?async呢?

    //Promise
    const sleep = time => {
      return new Promise(resolve => setTimeout(resolve,time))
    }
    sleep(1000).then(()=>{
      console.log(1)
    })
    
    //Generator
    function* sleepGenerator(time) {
      yield new Promise(function(resolve,reject){
        setTimeout(resolve,time);
      })
    }
    sleepGenerator(1000).next().value.then(()=>{console.log(1)})
    
    //async
    function sleep(time) {
      return new Promise(resolve => setTimeout(resolve,time))
    }
    async function output() {
      let out = await sleep(1000);
      console.log(1);
      return out;
    }
    output();
    
    //ES5
    function sleep(callback, time) {
      if(typeof callback === 'function')
        setTimeout(callback,time)
    }
    function output(){
      console.log(1);
    }
    sleep(output,1000);
    
  15. $nextTick?

    • 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
    • Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.thenMessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0)代替。
    • 例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
  16. 不在DOM中添加toast,调用全局API来显示toast,比如toast('success')

    // main.js
    import Toast from './components/toast/index'
    
    Vue.use(Toast)  //安装toast插件
    
    // components/toast/index.js
    import Toast from './Toast'
    
    const obj = {}  //对象
    
    obj.install = function(Vue) {  //封装install方法
      // 1. 创建组件构造器
      const toastContrustor = Vue.extend(Toast)
    
      // 2. new  组件实例
      const toast = new toastContrustor();
    
      // 3. 将组件实例, 挂载到某一个元素上
      toast.$mount(document.createElement('div'))
    
      // 4. toast.$el 对应的就是div
      document.body.appendChild(toast.$el);
        
      // 5. 添加到原型链上
      Vue.prototype.$toast = toast
      
    }
    
    export default obj