Skip to content

1、vue2、vue3数据绑定的实现原理?

1)响应式原理api的改变

​ Vue2响应式原理采用的是defineProperty,而vue3选用的是proxy。这两者前者是修改对象属性的权限标签,后者是代理整个对象。性能上proxy会更加优秀。

2)diff算法,渲染算法的改变

​ Vue3优化diff算法。不再像vue2那样比对所有dom,而采用了block tree的做法。此外重新渲染的算法里也做了改进,利用了闭包来进行缓存。这使得vue3的速度比vue2快了6倍。

image-20220315214411107

2、定位(position )

absolute 绝对定位

relative 相对定位

未知大小的子元素在父元素中居中:

html
父元素{
 /* 相对定位 */
 position: relative;
}
子元素{
 /* 绝对定位 */
 position:absolute;
 left:0;
 top:0;
 right:0;
 bottom:0;
 margin:auto;
}
javascript
display: flex; // 子元素 就变成块元素了
/* 交叉轴对齐方式 */
语法:align-items: flex-start|flex-end|center|baseline|stretch;
/* 轴的方向 */
语法:flex-direction: row|row-reverse|column|column-reverse;

3、css盒模型

外边距(margin)、边框(border)、内边距(padding)、实际内容(content)四个属性。

1)标准模型(box-sizing:conent-box;)

margin、border、padding、content

盒子总宽度/高度 = width/height + padding + border + margin

即 width/height 只是内容高度,不包含 padding 和 border 值

2)怪异盒模型(box-sizing: border-box;)

盒子总宽度/高度 = width/height + margin = (内容区宽度/高度 + padding + border) + margin

即 width/height 包含了 padding 和 border 值

4、vue-router的原理?

https://blog.csdn.net/weixin_43964148/article/details/107647319

5、v8引擎的垃圾回收机制?

1)引用计数 当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被销 毁掉 2)标记清除 设置一个根对象,垃圾回收器会定时从这个根开始,去查找有引用根对象的对象。对于哪些没有引用到的对象,他就会清除

6、vue.nextTick()的实现原理?

https://www.cnblogs.com/leiting/p/13174545.html

7、并发模型与事件循环?

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop

8、微观任务、宏观任务的执行顺序?

https://juejin.cn/post/6844904138606641166

https://blog.csdn.net/m0_46149187/article/details/112249636

9、vue中对某些数组的api,无法监听的处理方式?

https://blog.csdn.net/qq_15509267/article/details/88086810

1)vue无法监听的数组变化的场景:

① 通过数组索引改变数组元素的值;

② 改变数组的长度;

2)VUE解决无法监听数组变化的方法

① this.$set(arr, index, newVal);

② 通过splice(index,num,val)

③ 使用临时变量作为中转,重新赋值数组;

10、重绘、重排?

1)浏览器的运行机制(layout 布局)

① 构建DOM树(parse):渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node(包括js生成的标签)生成内容树(Content Tree/DOM Tree);

②构建渲染树(construct):解析对应的CSS样式文件信息(包括js生成的样式和外部css文件),而这些文件信息以及HTML中可见的指令(如),构建渲染树(Rendering Tree/Frame Tree);

③ 布局渲染树(reflow/layout):从根节点递归调用,计算每一个元素的大小、位置等,给出每个节点所应该在屏幕上出现的精确坐标;

④ 绘制渲染树(paint/repaint):遍历渲染树,使用UI后端层来绘制每个节点。

2)重绘(repaint或redraw)

​ 当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。

重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。

触发重绘的条件:改变元素外观属性。如:color,background-color等。

​ 注意:table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是我们尽量避免使用table布局页面的原因之一。

3)重排(回流)

​ 当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。所以,重排必定会引发重绘,但重绘不一定会引发重排。

​ 触发重排的条件:任何页面布局和几何属性的改变都会触发重排,比如:

① 页面渲染初始化;(无法避免)

② 添加或删除可见的DOM元素;

③ 元素位置的改变,或者使用动画;

④ 元素尺寸的改变——大小,外边距,边框;

⑤ 浏览器窗口尺寸的变化(resize事件发生时);

⑥ 填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变;

⑦ 读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )

4)优化

① 浏览器自己的优化:浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。

② 我们要注意的优化:我们要减少重绘和重排就是要减少对渲染树的操作,则我们可以合并多次的DOM和样式的修改。并减少对style样式的请求。

a、直接改变元素的className

b、display:none;先设置元素为display:none;然后进行页面布局等操作;设置完成后将元素设置为display:block;这样的话就只引发两次重绘和重排;

c、不要经常访问浏览器的flush队列属性;如果一定要访问,可以利用缓存。将访问的值存储起来,接下来使用就不会再引发回流;

d、使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;

e、将需要多次重排的元素,position属性设为absolute或fixed,元素脱离了文档流,它的变化不会影响到其他元素;

f、如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document;

11、虚拟DOM和真实dom的区别、优点?

1)是什么?

Real DOM,真实DOM, 意思为文档对象模型,是一个结构化文本的抽象,在页面渲染出的每一个结点都是一个真实DOM结构,如下:

img

Virtual Dom(虚拟DOM),本质上是以 JavaScript 对象形式存在的对 DOM 的描述

创建虚拟DOM目的就是为了更好将虚拟的节点渲染到页面视图中,虚拟DOM对象的节点与真实DOM的属性一一照应

在React中,JSX是其一大特性,可以让你在JS中通过使用XML的方式去直接声明界面的DOM结构

const vDom = <h1>Hello World</h1> // 创建h1标签,右边千万不能加引号
const root = document.getElementById('root') // 找到<div id="root"></div>节点
ReactDOM.render(vDom, root) // 把创建的h1标签渲染到root节点上

上述中,ReactDOM.render()用于将你创建好的虚拟DOM节点插入到某个真实节点上,并渲染到页面上

JSX实际是一种语法糖,在使用过程中会被babel进行编译转化成JS代码,上述VDOM转化为如下:

const vDom = React.createElement(
  'h1', 
  { className: 'hClass', id: 'hId' },
  'hello world'
)

可以看到,JSX就是为了简化直接调用 React.createElement() 方法:

  • 第一个参数是标签名,例如h1、span、table...

  • 第二个参数是个对象,里面存着标签的一些属性,例如id、class等

    第三个参数是节点中的文本

通过console.log(VDOM),则能够得到虚拟VDOM消息

img

所以可以得到,JSX通过babel的方式转化成React.createElement执行,返回值是一个对象,也就是虚拟DOM

2)两者的区别如下

虚拟DOM不会进行回流与重绘操作,而真实DOM会频繁回流与重绘

虚拟DOM的总损耗是“虚拟DOM增删改+真实DOM差异增删改+排版与重绘”,真实DOM的总损耗是“真实DOM完全增删改+排版与重绘”

拿以前文章举过的例子:

传统的原生api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程

当你在一次操作时,需要更新10个DOM节点,浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程

而通过VNode,同样更新10个DOM节点,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,避免大量的无谓计算

3)优缺点

真实DOM的优势:

易用 缺点:

效率低,解析速度慢,内存占用量过高 性能差:频繁操作真实DOM,易于导致重绘与回流

使用虚拟DOM的优势如下:

简单方便:如果使用手动操作真实DOM来完成页面,繁琐又容易出错,在大规模应用下维护起来也很困难

性能方面:使用Virtual DOM(虚拟DOM),能够有效避免真实DOM数频繁更新,减少多次引起重绘与回流,提高性能

跨平台:Vue借助虚拟DOM, 带来了跨平台的能力,一套代码多端运行

缺点:

在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化

首次渲染大量DOM时,由于多了一层虚拟DOM的计算,速度比正常稍慢

12、数组扁平化?

https://juejin.cn/post/6844903805876699150

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

13、为什么Promise可以一直点then?

因为Promise会返回一个Promise

https://segmentfault.com/q/1010000022049517/a-1020000022053181

14、Http状态码?

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599):

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

HTTP状态码列表:

状态码状态码英文名称中文描述
100Continue继续。客户端应继续其请求
101Switching Protocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200OK请求成功。一般用于GET与POST请求
201Created已创建。成功请求并创建了新的资源
202Accepted已接受。已经接受请求,但未处理完成
203Non-Authoritative Information非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204No Content无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205Reset Content重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206Partial Content部分内容。服务器成功处理了部分GET请求
300Multiple Choices多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301Moved Permanently永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302Found临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303See Other查看其它地址。与301类似。使用GET和POST请求查看
304Not Modified未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305Use Proxy使用代理。所请求的资源必须通过代理访问
306Unused已经被废弃的HTTP状态码
307Temporary Redirect临时重定向。与302类似。使用GET请求重定向
400Bad Request客户端请求的语法错误,服务器无法理解
401Unauthorized请求要求用户的身份认证
402Payment Required保留,将来使用
403Forbidden服务器理解请求客户端的请求,但是拒绝执行此请求
404Not Found服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405Method Not Allowed客户端请求中的方法被禁止
406Not Acceptable服务器无法根据客户端请求的内容特性完成请求
407Proxy Authentication Required请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408Request Time-out服务器等待客户端发送的请求时间过长,超时
409Conflict服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410Gone客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411Length Required服务器无法处理客户端发送的不带Content-Length的请求信息
412Precondition Failed客户端请求信息的先决条件错误
413Request Entity Too Large由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414Request-URI Too Large请求的URI过长(URI通常为网址),服务器无法处理
415Unsupported Media Type服务器无法处理请求附带的媒体格式
416Requested range not satisfiable客户端请求的范围无效
417Expectation Failed服务器无法满足Expect的请求头信息
500Internal Server Error服务器内部错误,无法完成请求
501Not Implemented服务器不支持请求的功能,无法完成请求
502Bad Gateway作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503Service Unavailable由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504Gateway Time-out充当网关或代理的服务器,未及时从远端服务器获取请求
505HTTP Version not supported服务器不支持请求的HTTP协议的版本,无法完成处理

15、强弱缓存?

https://segmentfault.com/a/1190000015245578

16、数组的方法(map的实现,为什么可以一直map)

https://juejin.cn/post/6863350138773979144

javascript
Array.prototype.map = function (cb, thisArg) {
    if (!Array.isArray(this) || typeof cb != 'function') {
        throw new Error('has Error, please check!')
    }
    var res = []
    for (var i = 0; i < this.length; i++) {
        //使用call方法来改变this指向即可
        res.push(cb.call(thisArg, this[i], i, this))
    }
    return res;
}
// 测试
var arr = [ 1, 2, 3, 4 ]
var obj = { name: 'jakeQuc', age: 18 }
var res = arr.map(function (item, index, arr) {
    item + 1;
    //此处的this就是传进来的obj,调用多少次就打印多少次
    // 如果此处使用箭头函数this指向的是window,你应该懂的哈
    console.log(this)
}, obj)
console.log(res); // [2,3,4,5]

注:map也不会返回一个新数组,如果 你要返回新数组,那么 你就要return

17、类型判断

https://www.cnblogs.com/onepixel/p/5126046.html

javascript
console.log(Number(null)) // 0
console.log(Number({})) // NaN

18、单例模式可以做些什么?(设计者模式)

https://juejin.cn/post/6909737165157203982

http://huasenjio.top/article/interview#directory09348302126534578130

19、箭头函数和function的区别(除了this)?

https://segmentfault.com/a/1190000018477740

20、http和https的区别?

https://www.runoob.com/w3cnote/http-vs-https.html

21、Vue 组件 data 为什么必须是函数?

https://juejin.cn/post/6844903478901358605

http://gaocarri.top/post/vue关于data为什么是函数这件事/

22、冒泡排序、二叉树

1)冒泡排序

相邻的两个数进行比较,若前一个大于后一个,则交换两个数的位置,以此类推

javascript
let arr = [ 9, 8, 3, 7, 66 ]
function fun(arr){
    for (let i = 0; i < arr.length-1; i++){
        for (let j = 0; j < arr.length - 1 - i; j++){
            /**
             * 比较大小
             */
            if(arr[j] > arr[j+1]){
                let temp = arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = temp
            }
        }
    }
    return arr
}

console.log(fun(arr))

2)选择排序

1

23、字符串倒序

javascript
function fun(str) {
    let stack = [];//生成一个栈
    for (let len = str.length, i = len; i >= 0; i--) {
        stack.push(str[i]);
    }
    /**
     * join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串
     * 里面可传入拼接参数
     */
    return stack.join('');
}

console.log(fun("12345678"))

https://codeantenna.com/a/v3TWVKc0Ig

24、数组去重

javascript
function fun(arr) {
    let newArr = []
    for (let i in arr) {
        let bool = false
        for(let j in newArr){
            if (newArr[j] === arr[i]){
                bool = true
                break
            }
        }
        if (bool === false) newArr.push(arr[i])
    }
    return newArr
}

console.log(fun([ 1, 2, 3, 4, 1, 2 ]))

25、v-if和v-for的执行顺序?

由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。

解决办法:

  1. 在v-for的外层或内层包裹一个元素来使用v-if
  2. 用computed处理

26、子夫组件中那个mounted先执行

tex
父beforeCreate -> 
父created -> 
父beforeMount-> 
子beforeCreate -> 
子created -> 
子beforeMount->
子mounted->
父mounted

27、Promise.all的实现

https://zhuanlan.zhihu.com/p/41502945

28、找出数组中的最大值

javascript
    let arr = [ 111, 2, 4, 5, 12, 2, 133 ]
    /**
     * 第一种 *
     */
    Array.prototype.max = function () {
        let max = this[0]
        for (let i of arr) {
            max = max > i ? max : i
        }
        return max
    }
    console.log(arr.max())
    /**
     * 第二种
     */
    let arr1 = arr.sort((a, b) => {
        return b - a
    })[0]
    console.log(arr1)
    /**
     * 第三种
     */
    let arr2 = Math.max.apply(null, arr)
    console.log(arr2)
    console.log(Math.max(...arr));

基于 MIT 许可发布