前端面试题 day1

Scroll Down

一、什么是虚拟Dom

展开查看 从本质上来说,Virtual Dom是一个JavaScript对象,通过对象的方式来表示DOM结构。将页面的状态抽象为JS对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次DOM修改的结果一次性的更新到页面上,从而有效的减少页面渲染的次数,减少修改DOM的重绘重排次数,提高渲染性能。

虚拟dom是对DOM的抽象,这个对象是更加轻量级的对DOM的描述。它设计的最初目的,就是更好的跨平台,比如Node.js就没有DOM,如果想实现SSR,那么一个方式就是借助虚拟dom, 因为虚拟dom本身是js对象。

在代码渲染到页面之前,vue或者react会把代码转换成一个对象(虚拟DOM)。以对象的形式来描述真实dom结构,最终渲染到页面。在每次数据发生变化前,虚拟dom都会缓存一份,变化之时,现在的虚拟dom会与缓存的虚拟dom进行比较。

在vue或者react内部封装了diff算法,通过这个算法来进行比较,渲染时修改改变的变化,原先没有发生改变的通过原先的数据进行渲染。

另外现代前端框架的一个基本要求就是无须手动操作DOM,一方面是因为手动操作DOM无法保证程序性能,多人协作的项目中如果review不严格,可能会有开发者写出性能较低的代码,另一方面更重要的是省略手动DOM操作可以大大提高开发效率。

二、为什么要用 Virtual DOM

展开查看 1.保证性能下限,在不进行手动优化的情况下,提供过得去的性能 看一下页面渲染的一个流程:

解析HTNL ☞ 生成DOM🌲 ☞ 生成 CSSOM ☞ Layout ☞ Paint ☞ Compiler
下面对比一下修改DOM时真实DOM操作和Virtual DOM的过程,来看一下它们重排重绘的性能消耗:

真实DOM: 生成HTML字符串 + 重建所有的DOM元素
Virtual DOM: 生成vNode + DOMDiff + 必要的dom更新
Virtual DOM的更新DOM的准备工作耗费更多的时间,也就是JS层面,相比于更多的DOM操作它的消费是极其便宜的。尤雨溪在社区论坛中说道: 框架给你的保证是,你不需要手动优化的情况下,我依然可以给你提供过得去的性能。

2.跨平台
Virtual DOM本质上是JavaScript的对象,它可以很方便的跨平台操作,比如服务端渲染、uniapp等。

三、Virtual DOM真的比真实DOM性能好吗

展开查看 首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。 正如它能保证性能下限,在真实DOM操作的时候进行针对性的优化时,还是更快的。

编程题

第 1 题:写一个 mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b,...,a+nb 的时间,然后写一个 myClear,停止上面的 mySetInterVal

展开查看
 
function mySetInterVal(fn, a, b) {
    this.a = a;
    this.b = b;
    this.time = 0;
    this.handle = -1;
    this.start = () => {
        this.handle = setTimeout(() => {
            fn();
            this.time++;
            this.start();
            console.log( this.a + this.time * this.b);
        }, this.a + this.time * this.b);
    }
this.stop = () => {
    clearTimeout(this.handle);
    this.time = 0;
}

}

var a = new mySetInterVal(() => {console.log('123')},1000, 2000 );
a.start();
a.stop();

2.合并二维有序数组成一维有序数组,归并排序的思路

展开查看
 

/**

  • 解题思路:
  • 双指针 从头到尾比较 两个数组的第一个值,根据值的大小依次插入到新的数组中
  • 空间复杂度:O(m + n)
  • 时间复杂度:O(m + n)
  • @param arr1
  • @param arr2
    */

function merge(arr1, arr2){
var result=[];
while(arr1.length>0 && arr2.length>0){
if(arr1[0]<arr2[0]){
/shift()方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。/
result.push(arr1.shift());
}else{
result.push(arr2.shift());
}
}
return result.concat(arr1).concat(arr2);
}

function mergeSort(arr){
let lengthArr = arr.length;
if(lengthArr === 0){
return [];
}
while(arr.length > 1){
let arrayItem1 = arr.shift();
let arrayItem2 = arr.shift();
let mergeArr = merge(arrayItem1, arrayItem2);
arr.push(mergeArr);
}
return arr[0];
}
let arr1 = [[1,2,3],[4,5,6],[7,8,9],[1,2,3],[4,5,6]];
let arr2 = [[1,4,6],[7,8,10],[2,6,9],[3,7,13],[1,5,12]];
mergeSort(arr1);
mergeSort(arr2);