全栈面试问题整理

java

  1. 介绍下位操作符&(与)、|(或)、^(异或,相同是为0)、~(取反)、<<(左移)、>>(右移)

  2. 堆、栈、静态区

    image-20210222113706668

  3. String str="i"与 String str=new String("i")一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。

  1. 重写override,能够重写一个函数需要满足哪些条件,哪些方法不能重新(static、final、private

  2. 函数执行顺序,对象中静态代码块是在对象第一次构造时执行,且是第一个执行

    public class className {
        {
            System.out.println("匿名代码块");  //第2个执行   一般可赋初始值
        }
        static {
            System.out.println("静态代码块");  //第1个执行,且只执行一次,再new时不执行
        }
        public className () {
            System.out.println("构造方法");    //第3个执行
        }
    }
    
  3. 接口(interface)和抽象类的区别是什么

    image-20210222134909049

  4. 创建线程有哪些方式

    线程创建方式

  5. 线程间通信的方式有哪些

  6. HashMap底层数据结构?为什么数组的长度必须是2的指数次幂?

  • JDK1.7及之前:数组+链表
  • JDK1.8:数组+链表+红黑树
  1. 单点登录系统session和cookie实现原理

  2. MyBatis的优点

    答:只回答了写mysql更加简单,回答要点不全

  3. MyBatis的二级缓存怎样开启,有什么缺点。

  4. java 中操作字符串都有哪些类?它们之间有什么区别?

操作字符串的类有:String、StringBuffer、StringBuilder。



String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。



StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
  1. mybatis 有几种分页方式?

    1. 数组分页
    2. sql分页
    3. 拦截器分页
    4. RowBounds分页
  2. mybatis 是否支持延迟加载?延迟加载的原理是什么?

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。



它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。



当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。

网络编程

  1. TCP的三次握手和四次挥手
  2. 当我在地址栏里输入一个地址,按下回车到页面展示信息,这个过程发生了什么?越详细越好。
  3. image-20210224212157763

数据库

  1. ACID是什么(MySQL)?

  2. 什么是事务?

  3. MySQL的事物隔离级别有哪些?用过哪些?默认的是(可重复读)?

    image-20210222125447817

  4. 高并发时,如何安全地修改同一行数据(悲观锁)

存储引擎的对比
特性 InnoDB MyISAM MEMORY
事务安全 支持
存储限制 64TB
空间使用
内存使用
插入数据的速度
对外键的支持 支持
  1. redis的持久化方法?支持事务吗?用过哪种?

  2. Redis的高并发和快速原因

1.redis是基于内存的,内存的读写速度非常快;

2.redis是单线程的,省去了很多上下文切换线程的时间;

3.redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。

  1. 为什么Redis是单线程的

1.官方答案

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

2.性能指标

关于redis的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。

3.详细原因

1)不需要各种锁的性能消耗

Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除

一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。

总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

2)单线程多进程集群方案

单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

所以单线程、多进程的集群不失为一个时髦的解决方案。

3)CPU消耗

采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。

但是如果CPU成为Redis瓶颈,或者不想让服务器其他CUP核闲置,那怎么办?

可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程上就可以了。

  1. Redis单线程的优劣势

单进程单线程优势

  1. 代码更清晰,处理逻辑更简单
  2. 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
  3. 不存在多进程或者多线程导致的切换而消耗CPU

单进程单线程弊端

  1. 无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善;

  2. redis中hash这种数据结构底层是怎么存储的?

    Redis的Hash,就是在数组+链表的基础上,进行了一些rehash优化等。

微服务

  1. 给你一个商城系统,让你拆分,你会怎么拆?

操作系统

  1. 进程调度

    调度种类

    • 高级调度:(High-Level Scheduling)又称为作业调度,它决定把后备作业调入内存运行
    • 低级调度:(Low-Level Scheduling)又称为进程调度,它决定把就绪队列的某进程获得CPU
    • 中级调度:(Intermediate-Level Scheduling)又称为在虚拟存储器中引入,在内、外存对换区进行进程对换

    非抢占式调度与抢占式调度

    • 非抢占式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度进程调度某事件而阻塞时,才把处理机分配给另一个进程
    • 抢占式:操作系统将正在运行的进程强行暂停,由调度程序将CPU分配给其他就绪进程的调度方式

    调度算法

    FIFO或First Come, First Served (FCFS)先来先服务

    • 调度的顺序就是任务到达就绪队列的顺序
    • 公平、简单(FIFO队列)、非抢占、不适合交互式
    • 未考虑任务特性,平均等待时间可以缩短

    Shortest Job First (SJF)

    • 最短的作业(CPU区间长度最小)最先调度
    • SJF可以保证最小的平均等待时间

    Shortest Remaining Job First (SRJF)

    • SJF的可抢占版本,比SJF更有优势
    • SJF(SRJF): 如何知道下一CPU区间大小?根据历史进行预测: 指数平均法

    优先权调度

    • 每个任务关联一个优先权,调度优先权最高的任务
    • 注意:优先权太低的任务一直就绪,得不到运行,出现“饥饿”现象

    Round-Robin(RR)轮转调度算法

    • 设置一个时间片,按时间片来轮转调度(“轮叫”算法)
    • 优点: 定时有响应,等待时间较短;缺点: 上下文切换次数较多
    • 时间片太大,响应时间太长;吞吐量变小,周转时间变长;当时间片过长时,退化为FCFS

    多级队列调度

    • 按照一定的规则建立多个进程队列
    • 不同的队列有固定的优先级(高优先级有抢占权)
    • 不同的队列可以给不同的时间片和采用不同的调度方法
    • 存在问题1:没法区分I/O bound和CPU bound
    • 存在问题2:也存在一定程度的“饥饿”现象

    多级反馈队列

    • 在多级队列的基础上,任务可以在队列之间移动,更细致的区分任务
    • 可以根据“享用”CPU时间多少来移动队列,阻止“饥饿”
    • 最通用的调度算法,多数OS都使用该方法或其变形,如UNIX、Windows等
  2. 线程同步的方式有哪些?

    • 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
    • 信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
    • 事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
  3. 进程的通信方式有哪些?

    主要分为:管道、系统IPC(包括消息队列、信号量、共享存储)、SOCKET

    管道主要分为:普通管道PIPE 、流管道(s_pipe)、命名管道(name_pipe

    • 管道是一种半双工的通信方式,数据只能单项流动,并且只能在具有亲缘关系的进程间流动,进程的亲缘关系通常是父子进程
    • 命名管道也是半双工的通信方式,它允许无亲缘关系的进程间进行通信
    • 信号量是一个计数器,用来控制多个进程对资源的访问,它通常作为一种锁机制。
    • 消息队列是消息的链表,存放在内核中并由消息队列标识符标识。
    • 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
    • 共享内存就是映射一段能被其它进程访问的内存,这段共享内存由一个进程创建,但是多个进程可以访问。
  4. 分页和分段有什么区别?

    • 段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。
    • 段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定
    • 段向用户提供二维地址空间;页向用户提供的是一维地址空间
    • 段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。
  5. Linux中常用到的命令

    显示文件目录命令ls 如ls

      改变当前目录命令cd 如cd /home

      建立子目录mkdir 如mkdir xiong

      删除子目录命令rmdir 如rmdir /mnt/cdrom

      删除文件命令rm 如rm /ucdos.bat

      文件复制命令cp 如cp /ucdos /fox

      获取帮助信息命令man 如man ls

      显示文件的内容less 如less mwm.lx

      重定向与管道type 如type readme>>direct,将文件readme的内容追加到文direct中

  6. makefile文件的作用是什么?

    一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中。makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”。一旦写好,只需要一个make命令,整个工程完全自动编译,极大地提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具。一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

算法

  1. 给你一个长度为 n 的数组,其中只有一个数字出现了奇数次,其他均出现偶数次,问如何使用优秀的时空复杂度快速找到这个数字。(异或)

  2. 给你一个长度为 n 的数组,其中只有一个数字出现了大于等于 n/2 次,问如何使用优秀的时空复杂度快速找到这个数字。

  3. 1000水有一瓶毒,用10只老鼠一次找到毒药?

  4. 插入排序

    package 排序;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class InsertSort {
    	//输出排序前后的时间,看看大概需要花多久
        public static void main(String[] args){
            SimpleDateFormat startTime = new SimpleDateFormat("yyyy:MM:dd:HH:mm:ss");
            System.out.println("排序开始时间:"+startTime.format(new Date()));
    
            sort();
            
            SimpleDateFormat endTime = new SimpleDateFormat("yyyy:MM:dd:HH:mm:ss");
            System.out.println("排序结束时间:"+endTime.format(new Date()));
    
        }
    
        public static void sort(){
            //测试80万个数据的排序
            int[] arr = new int[800000];
            for (int index = 0; index < 800000; index++) {
                arr[index] = (int)(Math.random() * 80000);
            }
    
            for (int i = 1; i < arr.length; i++) {
                int j = i;
                while (j > 0){
                    if (arr[j] < arr[j-1]){
                        int temp ;
                        temp = arr[j];
                        arr[j] = arr[j-1];
                        arr[j-1] = temp;
                        //System.out.println(Arrays.toString(arr));
                        j--;
                    }else {
                        break;
                    }
                }
            }
            //System.out.println(Arrays.toString(arr));
        }
    }
    
  5. 排序

    image-20210224214003565

不存在最好的排序算法,我们需要根据上面这些性能选择合适的方法,甚至是结合使用。下面是我从一篇腾讯新闻里看到的:
(1)当数据规模较小时候,可以使用简单的直接插入排序或者直接选择排序。
(2)当文件的初态已经基本有序,可以用直接插入排序和冒泡排序。
(3)当数据规模较大时,应用速度最快的排序算法,可以考虑使用快速排序。当记录随机分布的时候,快速排序平均时间最短,但是会出现最坏的情况,这个时候的时间复杂度是O(n^2),且递归深度为n,所需的占空间为O(n)。
(4)堆排序不会出现快排那样最坏情况,且堆排序所需的辅助空间比快排要少,但是这两种算法都不是稳定的,要求排序时是稳定的,可以考虑用归并排序。
(5)归并排序可以用于内部排序,也可以使用于外部排序。在外部排序时,通常采用多路归并,并且通过解决长顺串的合并,加上长的初始串,提高主机与外设并行能力等,以减少访问外存额外次数,提高外排的效率。
(6)特殊的桶排序、基数排序都是稳定且高效的排序算法,但有一定的局限性:

WEB前端

  1. 讲讲输入完网址按下回车,到看到网页这个过程中发生了什么

  2. 谈谈你对前端性能优化的理解?

    a. 请求数量:合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域

    b. 请求带宽:开启GZip,精简JavaScript,移除重复脚本,图像优化,将icon做成字体

    c. 缓存利用:使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存

    d. 页面结构:将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出

    e. 代码校验:避免CSS表达式,避免重定向

  3. 请你谈谈Cookie的弊端

    a. 每个特定的域名下最多生成的cookie个数有限制

    b. IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie

    c. cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节

    d. 安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。

  4. web storage和cookie的区别

    a. Cookie的大小是受限的

    b. 每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽

    c. cookie还需要指定作用域,不可以跨域调用

    d. Web Storage拥有setItem,getItem等方法,cookie需要前端开发者自己封装setCookie,getCookie

    e. Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生

    f. IE7、IE6中的UserData通过简单的代码封装可以统一到所有的浏览器都支持web storage

  5. 线程与进程的区别

    a. 一个程序至少有一个进程,一个进程至少有一个线程

    b. 线程的划分尺度小于进程,使得多线程程序的并发性高

    c. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率

    d. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

    e. 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配

  6. 请说出三种减少页面加载时间的方法

    a. 尽量减少页面中重复的HTTP请求数量

    b. 服务器开启gzip压缩

    c. css样式的定义放置在文件头部

    d. Javascript脚本放在文件末尾

    e. 压缩合并Javascript、CSS代码

    f. 使用多域名负载网页内的多个文件、图片

  7. 对前端界面工程师这个职位是怎么样理解的?

    a. 前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好

    b. 参与项目,快速高质量完成实现效果图,精确到1px;

    c. 与团队成员,UI设计,产品经理的沟通;

    d. 做好的页面结构,页面重构和用户体验;

    e. 处理hack,兼容、写出优美的代码格式;

    f. 针对服务器的优化、拥抱最新前端技术。

  8. 一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。

    a. 图片懒加载,滚动到相应位置才加载图片。

    b. 图片预加载,如果为幻灯片、相册等,将当前展示图片的前一张和后一张优先下载。

    c. 使用CSSsprite,SVGsprite,Iconfont、Base64等技术,如果图片为css图片的话。

    d. 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。

  9. 谈谈以前端角度出发做好SEO需要考虑什么?

    a. 了解搜索引擎如何抓取网页和如何索引网页

    b. meta标签优化

    c. 关键词分析

    d. 付费给搜索引擎

    e. 链接交换和链接广泛度(Link Popularity)

    f. 合理的标签使用

  10. html5有哪些新特性、移除了那些元素?

    a. HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。

    b. 拖拽释放(Drag and drop) API

    c. 语义化更好的内容标签(header,nav,footer,aside,article,section)

    d. 音频、视频API(audio,video)

    e. 画布(Canvas) API

    f. 地理(Geolocation) API

    g. 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失

    h. sessionStorage 的数据在页面会话结束时会被清除

    i. 表单控件,calendar、date、time、email、url、search

    j. 新的技术webworker, websocket等

    移除的元素:

    a. 纯表现的元素:basefont,big,center, s,strike,tt,u;

    b. 对可用性产生负面影响的元素:frame,frameset,noframes;

  11. undefined和null的区别

    null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。

    undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。

    null是javascript的*关键字,*可以认为是对象类型,它是一个空对象指针,和其它语言一样都是代表“空值”,不过 undefined 却是javascript才有的。undefined是在ECMAScript第三版引入的,为了区分空指针对象和未初始化的变量,它是一个预定义的*全局变量*。没有返回值的函数返回为undefined,没有实参的形参也是undefined。

  12. 常见的HTTP状态码

    2开头 (请求成功)表示成功处理了请求的状态代码。

    200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
    201 (已创建) 请求成功并且服务器创建了新的资源。
    202 (已接受) 服务器已接受请求,但尚未处理。
    203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
    204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
    205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
    206 (部分内容) 服务器成功处理了部分 GET 请求。

    3开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

    300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
    301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
    302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
    303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
    304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
    305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
    307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

    4开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。

    400 (错误请求) 服务器不理解请求的语法。
    401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
    403 (禁止) 服务器拒绝请求。
    404 (未找到) 服务器找不到请求的网页。
    405 (方法禁用) 禁用请求中指定的方法。
    406 (不接受) 无法使用请求的内容特性响应请求的网页。
    407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
    408 (请求超时) 服务器等候请求时发生超时。
    409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
    410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
    411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
    412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
    413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
    414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
    415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
    416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
    417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。

    5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

    500 (服务器内部错误) 服务器遇到错误,无法完成请求。
    501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
    502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
    503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
    504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
    505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

  13. 什么是防抖和节流?有什么区别?如何实现?

    防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

    思路:每次触发事件时都取消之前的延时调用方法

    节流:高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率

    思路:每次触发事件时都判断当前是否有等待执行的延时函数

  14. React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?

    vue 和 react 都是采用 diff 算法来对比新旧虚拟节点,从而更新节点。在 vue 的 diff函数中(建议先了解一下 diff 算法过程)。

    在交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的 key 去对比旧节点数组中的 key,从而找到相应旧节点(这里对应的是一个 key => index 的 map 映射)。如果没找到就认为是一个新增节点。而如果没有 key,那么就会采用遍历查找的方式去找到对应的旧节点。一种一个 map 映射,另一种是遍历查找。相比而言,map 映射的速度更快。

  15. 为什么虚拟 dom 会提高性能?

    虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。具体实现步骤如下:1. 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中。2. 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异。把 2 所记录的差异应用到步骤 1 所构建的真正的DOM树上,视图就更新了。

软实力

  1. 什么因素是决定你加入/离开一家公司
  2. 学习能力:通常怎么学习?
  3. 对自己技术的发展对话
  4. 平时的兴趣爱好
posted @ 2021-03-03 23:33  bGpi  阅读(1538)  评论(0编辑  收藏  举报