前端面试题Demo汇总
- 浏览器渲染原理
- 首先解析收到的文档,根据文档定义构建一颗 DOM 树,DOM 树是由 DOM 元素及属性节点组成的;
- 然后对 CSS 进行解析,生成 CSSOM 规则树;
- 根据 DOM 树和 CSSOM 规则树构建 Render Tree。渲染树的节点被称为渲染对象,渲染对象是一个包含有颜色和大小等属性的矩形,渲染对象和 DOM 对象相对应,但这种对应关系不是一对一的,不可见的 DOM 元素不会被插入渲染树。
- 当渲染对象被创建并添加到树中,它们并没有位置和大小,所以当浏览器生成渲染树以后,就会根据渲染树来进行布局(也可以叫做回流)。这一阶段浏览器要做的事情就是要弄清楚各个节点在页面中的确切位置和大小。通常这一行为也被称为“自动重排”。
- 布局阶段结束后是绘制阶段,比那里渲染树并调用对象的 paint 方法将它们的内容显示在屏幕上,绘制使用 UI 基础组件。
- 为了更好的用户体验,渲染引擎会尽可能早的将内容呈现到屏幕上,并不会等到所有的 html 解析完成之后再去构建和布局 render tree。它是解析完一部分内容就显示一部分内容,同时可能还在网络下载其余内容。
- 简述前端性能优化
- 页面内容方面
- 通过文件合并、css 雪碧图、使用 base64 等方式来减少 HTTP 请求数,避免过多的请求造成等待的情况;
- 通过 DNS 缓存等机制来减少 DNS 的查询次数;
- 通过设置缓存策略,对常用不变的资源进行缓存;
- 通过延迟加载的方式,来减少页面首屏加载时需要请求的资源,延迟加载的资源当用户需要访问时,再去请求加载;
- 通过用户行为,对某些资源使用预加载的方式,来提高用户需要访问资源时的响应速度;
- 服务器方面
- 使用 CDN 服务,来提高用户对于资源请求时的响应速度;
- 服务器端自用 Gzip、Deflate 等方式对于传输的资源进行压缩,减少传输文件的体积;
- 尽可能减小 cookie 的大小,并且通过将静态资源分配到其他域名下,来避免对静态资源请求时携带不必要的 cookie;
- 页面内容方面
- 标准盒模型和怪异盒模型 w3c标准盒模型: box-sizing: content-box盒子高度仅由content 宽高决定,不包含padding/border/margin IE盒魔性: box-sizing: border-box盒子高度包含 padding/border (常用)
- 浏览器重绘和回流
- 从浏览器地址栏输入 url 到显示页面的步骤
- Promise 相关
- 发布订阅 Event Emitter
- JS实现继承
- String 相关
- 项目优化方案
- 排序相关
- 隐式类型转换 == 的5条规则例题
- NaN和其他任何类型比较永远返回false(包括和他自己�)
- Boolean 和其他任何类型比较,Boolean 首先被转换为 Number 类型。
- String和Number比较,先将String转换为Number类型。
- null == undefined比较结果是true,除此之外,null、undefined和其他任何结果的比较值都为false。
- 原始类型和引用类型做比较时,引用类型会依照ToPrimitive规则转换为原始类型。
- webpack优化
- Event Loop Node和浏览器差异
- ES5/ES6 的继承除了写法以外还有什么区别?
- class 声明会提升,但不会初始化赋值。(类似于 let、const 声明变量;
- class 声明内部会启用严格模式;
- class 的所有方法(包括静态方法和实例方法)都是不可枚举的;
- class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有 [[constructor]],不能使用 new 来调用;
- 必须使用 new 来调用 class;
- class 内部无法重写类名;
- Async/Await 的原理
- 箭头函数与普通函数(function)的区别是什么?构造函数(function)可以使用 new 生成实例,那么箭头函数可以吗?为什么?
- 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象;
- 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
- 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数;
- 不可以使用 new 命令,因为:没有自己的 this,无法调用 call、apply;没有 prototype 属性,而 new 命令在执行时需要将钩子函数的 prototype 赋值给新的对象的 proto
- MVC、MVP、MVVM
- 执行上下文和执行栈
- 执行上下文
- 全局执行上下文:默认的上下文,任何不在函数内部的代码都在全局上下文里面。它会执行两件事情:创建一个全局的的 window 对象,并且设置 this 为这个全局对象。一个程序只有一个全局对象。
- 函数执行上下文:每当一个函数被调用时,就会为该函数创建一个新的上下文,每个函数都有自己的上下文,不过是在被函数调用的时候创建的。函数上下文可以有任意多个,每当一个新的执行上下文被创建,他会按照定义的顺序执行一系列的步骤。
- Eval 函数执行上下文:执行在 eval 函数内部的代码有他自己的执行上下文。
- 执行栈
- 执行栈就是一个调用栈,是一个后进先出数据结构的栈,用来存储代码运行时创建的执行上下文。
- this 绑定
- 全局执行上下文中,this 指向全局对象。
- 函数执行上下文中,this 取决于函数是如何被调用的。如果他被一个引用对象调用,那么 this 会设置成那个对象,否则是全局对象。
- 执行上下文
- js中常见的几种内存泄露
- 意外的全局变量;
- 闭包;
- 未被清空的定时器;
- 未被销毁的事件监听;
- DOM 引用;
- 实现 new
- React
- Vue
- vue name 作用
- keep-alive 使用 name 做缓存过滤
- 递归组件用 name 调用自身
- vue-devtools 展示名字
- Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题 ?你能说说如下代码的实现原理么?
- Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?
- Object.defineProperty 无法低耗费的监听到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
- Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历。如果属性值是对象,还需要深度遍历。 Proxy 可以劫持整个对象, 并返回一个新的对象。
- Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
- new Vue之后发生了什么?
- new Vue 会调用 Vue 原型链上的 _init 方法对 Vue 实例进行初始化;
- 首先是 initLifecycle 初始化生命周期,对 Vue 实例内部的一些属性(如 children、parent、isMounted)进行初始化;
- initEvents,初始化当前实例上的一些自定义事件(Vue.$on);
- initRender,解析 slots 绑定在 Vue 实例上,绑定 createElement 方法在实例上;
- 完成对生命周期、自定义事件等一系列属性的初始化后,触发生命周期钩子 beforeCreate;
- initInjections,在初始化 data 和 props 之前完成依赖注入(类似于 React.Context);
- initState,完成对 data 和 props 的初始化,同时对属性完成数据劫持内部,启用监听者对数据进行监听(更改);
- initProvide,对依赖注入进行解析;
- 完成对数据(state 状态)的初始化后,触发生命周期钩子 created;
- 进入挂载阶段,将 vue 模板语法通过 vue-loader 解析成虚拟 DOM 树,虚拟 DOM 树与数据完成双向绑定,触发生命周期钩子 beforeMount;
- 将解析好的虚拟 DOM 树通过 vue 渲染成真实 DOM,触发生命周期钩子 mounted;
- vue name 作用
- HTTP2多路复用
- 在 HTTP/1 中,每次请求都会建立一次 HTTP 连接,也就是我们常说的 3 次握手和 4 次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive,解决了多次连接的问题,但是依然有两个效率上的问题,一是串行的文件传输,二是连接数过多导致的性能问题。HTTP/2 的多路复用就是为了解决上述的两个性能问题。在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
- HTTP1.0和HTTP1.1的区别
- 缓存处理上: HTTP1.0里主要在 Header 中添加 If-Modified-Since/Expires 来做为缓存策略的标准,而 HTTP1.1引入了更多的缓存控制策略,如 Entity-tag/If-Unmodified-Since/If-Match/If-None-Match
- HTTP1.1支持长连接, 在一个TCP连接可以传送多个HTTP请求和响应,通过设置Connection: keep-alive,一定程度弥补了1.0每个请求都要创建连接的缺点
- 增加了24个错误状态码
- 带宽优化,1.1支持请求某个资源的某个部分,返回码206,Partial Content,有利于开发者自由选择,充分利用带宽和连接.
- HTTPS握手过程
- 客户端发送报文段,包含客户端生成的Random1和客户端支持的加密方法
- 服务端回复,将证书下发到客户端,同时携带服务端生成的Random2
- 客户端收到证书,验证证书合法性,过期时间,验证通过则取出证书中的服务端公钥,生成Random3,并用公钥非对称加密Random3生成PreMaster Key,发送到服务端
- 服务端用私钥解密preMaster key,获得random3, 客户端与服务端同时拥有3个Random,两遍在根据同样的算法,生成密钥。握手结束
- 之后所有的应用层数据都通过该密钥加密发送
- 优化点: 客户端发送的消息中存在上一次的SessionId,服务端收到后如果可以复用,就不在走握手过程.
- HTTPS客户端如何验证证书的合法性
- 验证证书是否在有效期内。
- 验证证书是否被吊销了。验证吊销有CRL和OCSP两种方法。
- CRL即证书吊销列表。证书被吊销后会被记录在CRL中,CA会定期发布CRL。应用程序可以依靠CRL来检查证书是否被吊销了。CRL有两个缺点,一是有可能会很大,下载很麻烦。针对这种情况有增量CRL这种方案。二是有滞后性,就算证书被吊销了,应用也只能等到发布最新的CRL后才能知道。增量CRL也能解决一部分问题,但没有彻底解决。
- OCSP是在线证书状态检查协议。应用按照标准发送一个请求,对某张证书进行查询,之后服务器返回证书状态。OCSP可以认为是即时的(实际实现中可能会有一定延迟),所以没有CRL的缺点。不过对于一般的应用来说,实现OCSP还是有些难度的。
- 验证证书是否是上级CA签发的。
- 什么是CDN
- CDN 是一个内容分发网络,通过对源网站资源的缓存,利用本身多台位于不同地域、不同运营商的服务器,向用户提供资源就近访问的功能。也就是说,用户的请求并不是直接发送给源网站,而是发送给 CDN 服务器,由 CDN 服务器将请求定位到最近的含有该资源的服务器上去请求。这样有利于提高网站的访问速度,同时通过这种方式也减轻了源服务器的访问压力。