你要的面试题在这呢

2,987 阅读12分钟

我找了好久的资料,终于把这道题整理完了,今天来续更了~

基础篇的第6题,如何验证数字证书的合法性。

今年,注定不平凡,经历的太多,感触太多。永远记住这句话:努力,并坚持,就会得到你想要的。

基础篇

1、我们都知道字符串是基本数据类型,基本类型是没有方法的,但为什么字符串还有很多方法?这个例子我用的是字符串的属性,原理都是一样的。

JavaScript为我们提供了三种特殊的包装用类型:String、Number和Boolean,方便我们操作对应的基本类型。在调用length的时候,JS引擎会先对原始类型数据进行包装,术语叫装箱。

执行这段代码是,JS引擎会从内存中读取str的值,然后会执行下面的操作:

  1. 创建String类型的一个实例 let newStr=new String();
  2. 在实例上调用该方法 let length=newStr.length;
  3. 销毁这个实例 newStr=null;

2、列出对数组产生副作用和没有副作用的方法(这道题很基础,背下来就行)

产生副作用的方法(改变了原来的数组):pop()、push() 、reverse() 、shift()、sort()、splice()、unshift()

没有副作用的方法(原来数组不变):concat()、join()、slice()、toString()、toLocaleString()、valueOf()

3、两列布局的几种实现方法(左侧固定,右侧自适应)

4、TCP三次握手

我在网上找了个图,先熟悉一下 最开始的时候客户端处于 Closed 的状态,服务端处于 Listen 状态。 接下来三次握手开始。

1、第一次握手:客户端给服务器发送SYN包,SYN=1,ACK=0表示这是一个连接请求报文段,所以我们看到SYN=1。同时初始化序列号seq=x,此时客户端处于SYN_SENT状态。

2、第二次握手:服务器收到SYN包后,确认客户的SYN,SYN=1,ACK=1表示同意连接,所以我们看到服务器应答中SYN=1,ACK=1。同时发送ACK报文,ack=x+1(客户端的序号(也就是x)+1),并且初始化序列号seq=y。此时服务器处于SYN_REVD状态。

3、第三次握手:客户端收到服务器的SYN+ACK包后,发送ACK报文,ack=y+1,标记序列号seq=x+1(客户端序列号为seq=x,第二个报文段所以要+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态。

注解:

序列号seq: 用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

确认号ack: 只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。

5、https加密过程

我们先简单了解一下对称加密和非对称加密

对称加密: 对称加密中使用的密钥叫做私钥,即同一个密钥既能加密又能解密,所以我们就能发现,如果被中间人拿到密钥,就没安全可言了。

非对称加密: 非对称加密使用的是一对密钥,即公钥和私钥。私钥只有服务器自己知道,公钥是公共的密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。即公钥加密,私钥解密,或者私钥加密,公钥解密。这里我们再想一下,如果中间人拿到公钥,还是可以对服务端传来的数据进行解密,所以还不是安全的。

对称加密和非对称加密的结合

https加密过程是采用对称加密和非对称加密的结合的方式,我们看下流程:

浏览器向服务器发送一个随机数加密方法列表

服务器接收到,返回另一个随机数加密方法(从加密方法列表选择的一个方法)以及公钥

浏览器接收,验证数字证书是否合法,如果验证不通过,拒绝执行。如果通过,会生成第三个随机数, 并且用公钥加密,传给服务器。

服务器用私钥解密加密过的第三个随机数。

浏览器和服务器用相同的加密方法混合这三个随机数,生成最终的密钥。 然后浏览器和服务器使用对称加密进行通信。中间人没有私钥,从而拿不到第三个随机数,也就无法生成最终的密钥了。

6、HTTPS 握手过程中,客户端如何验证证书的合法性

1、证书是否为值得信任有效证书。

  • 所谓信任是指,web服务器的证书是否为浏览器内置的根证书或根证书的二级证书机构颁发的。
  • 所谓有效是指,web服务器的证书是否在有效期内,是否已被吊销。

2、证书信息是否合法

  • CA进行数字证书的签名时会保存一个Hash算法,用这个算法来计算证书的hash值
  • 浏览器从内置的根证书里找到对应的CA机构公钥,解密证书中的数字签名得到摘要
  • 对比结果一致则表示认证合法。

7、讲讲JS的垃圾回收机制

我写了一篇关于垃圾回收机制的文章,大家点进去详细了解一下 juejin.cn/post/684490…

8、从浏览器输入url到页面的过程

这道题太经典,真的是每家必问,往大了说无止境,我建议是找文章深层的理解一下,关于dns解析,http发送请求等方面各文章都差不多,解析渲染这块有的说的很大,有的很简,所以我就整理总结了一下解析这块,便于面试的时候回答。

解析过程

1、构建DOM树(标记化和树的构建,又叫词法分析和语法分析)

  • 词法分析:字节流解析为token
  • 语法分析:开始结束标签配对,属性赋值,父子关系连接,DOM树转换为AST

2、样式计算

  • 格式化样式表

    浏览器无法直接识别CSS样式文本,渲染引擎接收到CSS文本时,会执行转换操作,将css转换成浏览器可以理解的结构,即styleSheets。在控制台输入document.styleSheets可以看其结构。

    样式表来源:①、link标签引用 ②、style标签中样式 ③、元素内嵌style属性
    
  • 转换属性值,使其标准化

    例如 rem转换px,color的blue等值转换成rgba形式,bold转换成数值700 等等
    
  • 计算DOM树中每个节点具体样式

    计算具体样式就涉及到两个规则:继承叠层

    继承:每个DOM节点都会默认继承父节点的样式。如果没有设置样式,就会采用浏览器默认样式,即UserAgent样式。

    叠层:叠层是CSS的一个基本特性,最终的样式取决于各个属性共同作用的效果。可以通过window.getComputedStyle来获取计算后的样式。

3、生成布局树

  • 遍历DOM节点,添加到布局树中
  • 计算布局树节点的坐标位置

4、屏幕绘制

  • 重排

    HTML采用的是从上到下的流式布局,css和js的加入会打破布局

  • 重绘

    改变DOM的样式、大小及位置

重排一定发生重绘,重绘不一定发生重排,重排很耗性能,所以coding过程中避免重排的发生

vue篇

1、vue响应式原理

当我们修改data里面的数据的时候,视图会进行更新。我们称之为响应式。

Vue 将遍历data里的所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。我们来看一下Object.defineProperty的最简单实现。

然后我们根据源码理解一下

首先定义了一个Observer的类,里面有进行对数组和对象的判断,我们这里不讨论数组和嵌套对象的情况。我们可以看到函数里面执行了对data的遍历,然后调用defineReactive函数。

接下来我们来看defineReactive这个函数,函数里面实例化一个依赖dep,然后执行了Object.defineProperty,其实依赖收集的过程就是把 Watcher 实例存放到对应的 Dep 对象中去(每个vue组件都绑定一个Watcher,Watcher是每个实例的观察者)。在get的时候,执行dep.depend(),这个函数内部调用了dep.addSub(),用于收集此属性和watcher这个观察者的依赖关系。在set的时候,执行了dep.notify(),内部所有的 Watcher 对象进行视图更新。(这个更新的过程,就是虚拟DOM的diff算法,来判断页面是否需要更新)

2、vue nextTick

Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。

我们可以看到,源码中,Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。可以看到,timerFunc内部有一个flushCallbacks的函数。

在执行nextTick的时候,会在callbacks这个数组里面储存所有回调。pending 是一个标记位,代表一个等待的状态。执行timerFunc,timerFunc是微任务,在下一个的事件循环“tick”中,执行timerFunc内部的flushCallbacks函数。flushCallbacks函数里面,把callbacks赋值给copies,清空callbacks(此步为清空任务队列),然后执行每一个回调。

为了在数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即使用Vue.nextTick(callback)。 created钩子(DOM未挂载),所以我们可以在这个钩子里执行某个操作。

3、vue computed 和 watch 区别?什么时候用computed,什么时候用watch?

computed是计算属性,为了模板简洁和利于维护,我们把复杂逻辑,在computed里面实现。注意:计算属性的 key 不能是 data 或者 prop 里面定义的key,否则会报错。computed是依赖watcher的实现的,那么他们俩有什么不同呢?

初始化的时候

计算属性不会求值,然后当我们的 render 函数执行访问到 computed相关依赖 的时候,就触发了计算属性的 getter,它会拿到计算属性对应的 watcher,然后执行 watcher.depend(),然后再去求值。

初始化过后

当computed的依赖发生变化的时候,就触发了计算属性的 getter,通知所有订阅它变化的 watcher 更新,执行 watcher.update() 方法。如果页面中没有订阅computed的变化,就不会求值,当下次再访问这个计算属性的时候才会重新求值。

我们要记住这一点,不仅仅是计算属性依赖的值发生变化,而是当计算属性最终计算的值发生变化才会触发渲染 watcher 重新渲染

watch是监听属性,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

watch 属性适用于观测某个值的变化去完成一段复杂的业务逻辑。

computed 属性适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来如果是一个属性,依赖多个属性变化的时候。

4、vue路由实现原理

vue路由是为了实现SPA(单页应用),vue是单页应用,所以当我们在页面进行一些操作改变路由的变化是,是不会向服务器发送请求的,浏览器监听到url的变化,从而更新页面。 有两种模式:

1、hash 例如 juejin.cn

hash模式是用hashchange的方法监听url,当URL的hash部分改变时,页面不会重新加载。并且向服务端发送的请求是juejin.cn部分

注意: 页面刷新的时候,不会向服务器发送请求

2、history 例如 juejin.cn

history模式充分利用 history.pushStateAPI来完成URL跳转而无须重新加载页面。主要使用 history.pushState、history.popState和history.replaceState改变URL。使用history模式,我们需要在路由里面加这行代码mode:history,然后需要后端配置一个覆盖所有情况的候选资源:如果URL匹配不到任何静态资源,则应该返回同一个index.html页面,这个页面就是你 app 依赖的页面。

router.push、 router.replace 和 router.go 跟 window.history.pushState、 window.history.replaceState 和 window.history.go好像, 实际上它们确实是效仿 window.history API 的。

注意: 页面刷新的时候,会向服务器发送请求

5、vuex是解决什么问题?数据流是怎样的?

数据流过程,状态改变到数据改变 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。解决组件共享状态的问题。Vuex是单向数据流。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。 在项目中,我们一般这么写来改变state的状态

同步形式:Mutation

1、提交载荷(payload):this.$store.commit(name,data)
commit触发mutation事件,name为state这个状态数其中的一个状态,data是一个额外的参数,即 mutation 的 载荷(payload)。在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读。

2、对象风格的提交方式:this.$store.commit({ type: name, data: value })

这种方式是直接使用包含 type 属性的对象,整个对象都作为载荷传给 mutation 函数

异步形式:Action

异步提交方式和同步一样,也是有载荷和对象风格两种形式,通过 this.$store.dispatch触发。不同的是,Action 内部会有接口的调用,但最终提交的是 mutation,而不是直接改变state的状态。这也是上面我们说到的 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation

手写篇 (注释部分重点看,是核心思想)

1、call

2、apply

3、bind

4、new

5、instanceof

6、防抖(带立即执行参数的防抖)

立即执行就是我们业务需要第一次点击的时候,就执行这个函数,之后的过程,如果在防抖期内,则进行防抖处理。

vue中怎么使用防抖,在模板上定义click方法@click="toast" ,在methods里面写toast方法

7、节流(带立即执行参数的节流)