跳槽人速来,记录一下大厂的前端面经

4,125 阅读11分钟

1.算法题:实现一个链接,可以新增节点,删除节点

function insert(head, n ,val) {
    var node = {
        val: val,
        next: null
    }
    if (head == null) {
        return node
    }
    if (n === 0) {
        node.next = head;
        return node;
    }

    var p = head;
    for(var i=0; i<n-1; i++){
        p = p.next;
    }
    node.next = p.next;
    p.next = node;
    return head;
}
function remove(head, n) {
    if (!head) {
        return null;
    }
    if (head === 0) {
        return head.next;
    }
    var p = head;
    for(var i=0; i<n-1; i++) {
        p = head.next;
    }
    p.next = p.next.next;
    return head;
}

2.实现一个instanceof方法

function myInstanceOf(left, right) {
    if (typeof left !== 'object' || left == null) {
        return false;
    }
    
    let pro = Object.getPrototypeOf(left);
    while(true) {
        if (pro === null) {
            return false;
        }
        if (pro === right.prototype) {
            return true;
        }
        pro = Object.getPrototypeOf(pro);
    }
}

3.响应式布局怎么实现 rem布局 flex布局

rem

(function(doc, win) {
   var docE1 = doc.documentElement,
       resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
       recalc = function() {
           var clientWidth = docE1.clientWidth;
           if (!clientWidth) return;
           docE1.style.fontSize = clientWidth / 7.5 + 'px';
       }
   
   if(!doc.addEventListener) return;
   win.addEventListener(resizeEvt, recalc, false);
   doc.addEventListener('DOMContentLoaded', recalc, false);  
})(document, window)

4.事件循环机制

  • 1.一开始整段脚本作为第一个宏任务执行
  • 2.执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  • 3.当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
  • 4.执行浏览器 UI 线程的渲染工作
  • 5.检查是否有Web worker任务,有则执行
  • 6.执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

5.设计模式:观察-订阅者模式 与 观察者模式的区别

6. https过程

HTTPS协议=HTTP协议+SSL/TLS协议,数据传输的过程中,需要使用SSl/TLS协议对数据进行加密和解密,需要用HTTP对加密后的数据进行传输,由此可以看出HTTPS是由HTTP和SSL/TLS一起合作完成的。

  • HTTPS为了兼顾安全与效率,同时使用了对称加密和非对称加密。
  • 数据是被对称加密传输的,对称加密过程需要客户端的一个密钥, 为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,
  • 总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。

为什么要使用对称加密?

原因:非对称加密基于大数运算,比如大素数或者椭圆曲线,是复杂的数学难题,所以消耗计算量,运算速度慢。除了慢,可能还有一个缺点就是需要更多的位数,相同强度的对称密钥要比非对称密钥短。对称密钥一般都128位、256位,而rsa一般要2048位,不过椭圆曲线的会短一点

7.http2的优化点

  1. 头部压缩: 采用HPACK算法,在客户端和服务端两端建立“字典”,用索引号表示重复的字符串, 还采用哈夫曼编码来压缩整数和字符串,可以到达50%-90%的高压缩率。

  2. 多路复用: 采用二进制分帧传输,不存在先后关系, 因此也就不会有等待排队,也就没有了HTTP 的对头阻塞问题。 通信双方都可以给对分发送二进制帧, 这种二进制帧的双向传输的序列,也叫做流。 HTTP/2用流来在一个TCP连接上来进行数据帧的通信, 这就是多路复用的概念。

  3. 设置请求优先级: 在二进制帧当中还有其它的一些字段, 实现了优先级和流量控制等功能

  4. 服务器推送 服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。

8.介绍csrf以及应对手段

CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事

应对手段:

  • 1.充分利用好 Cookie 的 SameSite 属性。 我们可以针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式, 这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。

    1. 验证请求的来源站点。 HTTP 请求头中的 Referer 和 Origin 属性 服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性, 再根据实际情况判断是否使用 Referer 值
    1. CSRF Token
      第一步,在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。 CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。 第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token, 然后服务器会验证该 Token 是否合法。如果是从第三方站点发出的请求, 那么将无法获取到 CSRF Token 的值,所以即使发出了请求, 服务器也会因为 CSRF Token 不正确而拒绝请求。

9.优化白屏的方式

  1. 提取第三方库,第三方依赖文件以及打包文件放进CDN服务器
  2. 对路由进行懒加载
  3. 首页白屏添加骨架屏或loading(仅仅是优化体验)
  4. 优化 webpack 减少模块打包体积,code-split 按需加载
  5. 服务端渲染,在服务端事先拼装好首页所需的 html
  6. 服务端开启gzip压缩
  7. element-ui等UI框架按需引入
  8. 打包文件分包,提取公共文件包
  9. 使用文件名增加hash名,解决新版本需要清除依赖的问题
  10. 代码压缩
  11. 压缩图片文件,减少文件体积
  12. 图片资源放进CDN服务器
  13. 使用CSS精灵图

10.继承与组合的优缺点

11.http缓存

1.先判断强缓存是否生效: 控制强缓存的字段分别是Expires和Cache-Control(优先级较高),

Expires:是HTTP/1.0控制网页缓存的字段, 值为服务器返回该请求结果缓存的到期时间
即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。
到了HTTP/1.1,Expire已经被Cache-Control替代

Cache-Control:主要取值
。 public:所有内容都将被缓存(客户端和代理服务器都可缓存)
。 private: 所有内容只有客户端可以缓存,Cache-Control的默认取值
。 no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
。 no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
。 max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

内存缓存(from memory cache)和硬盘缓存(from disk cache)
。内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
。快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,
  占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
。时效性:一旦该进程关闭,则该进程的内存则会清空。
。硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,
  读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
  
  在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,
  那么当刷新页面时只需直接从内存缓存中读取(from memory cache);
  而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

2.协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求, 由服务器根据缓存标识决定是否使用缓存的过程

控制协商缓存的字段分别有:Last-Modified/If-Modified-Since 和 Etag/If-None-Match(优先级高)

Last-Modified / If-Modified-Since:
    Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
    If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,
    通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。
    服务器收到该请求,发现请求头含有If-Modified-Since字段,
    则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,
    若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;
    否则则返回304,代表资源无更新,可继续使用缓存文件

Etag / If-None-Match :
    Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
    If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,
    通过此字段值告诉服务器该资源上次请求返回的唯一标识值。
    服务器收到该请求后,发现该请求头中含有If-None-Match,
    则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,
    继续使用缓存文件;不一致则重新返回资源文件,状态码为200,

总结: 
    强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,
    若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),
    协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,
    重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存  

12.require 与 import 的区别

  • 1.原生浏览器不支持 require/exports,可使用支持 CommonJS 模块规范的 Browsersify、webpack 等打包工具,它们会将 require/exports 转换成能在浏览器使用的代码。
  • 2.import/export 在浏览器中无法直接使用,我们需要在引入模块的
  • 3.即使 Node.js 13.2+ 已经支持 import/export,Node.js官方不建议在正式环境使用,目前可以使用 babel 将 ES6 的模块系统编译成 CommonJS 规范(注意:语法一样,但具体实现还 是require/exports)
    1. require/exports 是运行时动态加载,import/export 是静态编译
    1. require/exports 输出的是一个值的拷贝,import/export 模块输出的是值的引用
    1. ES6 模块可以在 import 引用语句前使用模块,CommonJS 则需要先引用后使用
    1. import/export 只能在模块顶层使用,不能在函数、判断语句等代码块之中引用;require/exports 可以
    1. 是否采用严格模式
    • import/export 导出的模块默认调用严格模式。
    • require/exports 默认不使用严格模式,可以自定义是否使用严格模式

13.箭头函数的实现

14.vue的双向绑定

    1. Data通过observer转换成了getter/setter的形式来追踪变化。
    1. 当外界通过Watcher读取数据时,会触发getter从而将Watch添加到依赖中。
    1. 当数据发生了变化时,会触发setter,从而向Dep中的依赖(即Watcher)发送通知
    1. Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新, 也有可能触发用户的某个回调函数等。

二面

1.离职原因

2.对 ts 的使用情况

3.观察者模式

4.单例模式

5.归并排序

function mergeSort(arr) {
    const len = arr.length;
    if (len <= 1 ) {
        return arr;
    }
    let mid = Math.floor(len / 2);
    let leftArr = mergeSort(arr.slice(0,mid));
    let rightArr = mergeSort(arr.slice(mid, len));
    arr = mergeArr(leftArr, rightArr);
    return arr;
}

function mergeArr(arr1, arr2){
    let i = 0;
    let j = 0;
    let len1 = arr1.length;
    let len2 = arr2.length;
    let res = [];
    while(i<len1 && j<len2) {
        if (arr1[i] < arr2[j]) {
            res.push(arr1[i])
            i++;
        } else {
            res.push(arr2[j])
            j++;
        }
    }
    if (i<len1) {
        return res.concat(arr1.slice(i));
    } else {
        return res.concat(arr2.slice(j));
    }
}

6.快速排序

function quickSort(arr, left=0; right=arr.length - 1) {
    if (arr.lenth > 1) {
        const lineIndex = partition(arr,left, right);
        if (left < lineIndex -1) {
            quickSort(arr,left,lineIndex -1);
        }
        if (right > lineIndex) {
            quickSort(arr,lineIndex,right);
        }
    }
    return arr;
}
function partition(arr, left, right) {
    let i = left;
    let j = right;
    let pivotValue = arr[Math.floor(left + (right-left)/2)];
    if (i<=j) {
        while(arr[i] < pivotValue) {
            i++
        }
        while(arr[j] > pivotValue) {
            j++
        }
        if (i<=j) {
            swap(arr,i,j);
            i++;
            j--;
        }    
    }
    return i;
}
function swap(arr,i,j){
    [arr[i],arr[j]] = [arr[j],arr[i]];
}

7.this 的使用

  • 1.在普通函数中使用 this, this代表全局对象window。
  • 2.作为一个对象的方法调用,此时this指的是调用它的那个对象。
  • 3.作为一个构造函数被调用,此时this指代new出来的那个对象。
  • 4.call调用 ,call方法的作用是改变函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象,this指的是第一个参数,如果不传参数,默认指的是全局对象window。

8.对 Http3 的了解

采用 QUIC 协议: HTTP/3 选择了一个折衷的方法——UDP 协议, 基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,我们把这套功能称为 QUIC 协议

HTTP/3 中的 QUIC 协议集合了以下几点功能:

  • 1.实现了类似 TCP 的流量控制、传输可靠性的功能
  • 2.集成了 TLS 加密功能
    1. 实现了 HTTP/2 中的多路复用功能。 和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流。 实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。

9.http2的优化点

(参考上面的)

10. 网络攻防 1. 主要有哪些问题 2. Xss 主要针对哪些字符进行转化

1.Xss: XSS 攻击就是黑客往页面中注入恶意脚本,然后将页面的一些重要数据上传到恶意服务器。 常见的三种攻击模式:1.存储型XSS攻击 2.反射性XSS攻击 3.基于DOM的XSS攻击

主要有三种防范策略: 第一种是通过服务器对输入的内容进行过滤或者转码, 第二种是充分利用好 CSP, 第三种是使用 HttpOnly 来保护重要的 Cookie 信息

2.Csrf(参看上面)

11.项目网络性能优化

12.主要使用哪个框架,vue源码相关的了解

13.对前沿技术的了解

最后:分享下自己整理的部分知识点文章链接