当前位置:   article > 正文

前端面试题汇总大全!

前端面试

前端面试题大全

文章目录


前端面试题汇总大全(含答案超详细)-- 持续更新

一、HTML 篇

1.xhtml和html有什么区别

  • 功能上
    • 主要是XHTML可兼容各大浏览器、手机以及PDA,并且浏览器也能快速正确地编译网页
  • 书写习惯
    • XHTML 元素必须被正确地嵌套,闭合,区分大小写,文档必须拥有根元素

2.行内元素有哪些?块级元素有哪些? 空(void)元素有那些?行内元素和块级元素有什么区别

行内元素有:a b span img input select strong
块级元素有:div ul ol li dl dt dd h1 h2 h3 h4…p
空元素:br、 hr img input link meta
行内元素不可以设置宽高,不独占一行
块级元素可以设置宽高,独占一行

3. 简述一下你对 HTML 语义化的理解?

语义化是指 根据内容的结构化(内容语义化),选择合适的标签(代码语义化)

语义化的好处:

  • 在没有CSS的情况下,页面也能呈现出很好的内容结构
  • 语义化使代码更具可读性,便于团队开发和维护
  • 语义化有利于用户体验(例如 title,label,alt属性的灵活运用)
  • 语义化有利于SEO(和搜索引擎建立良好的沟通,有助于爬虫爬取更多的有效信息。爬虫依赖于标签来确定上下文和各个关键字的权重)

4. 标签上 title 与 alt 属性的区别是什么?

alt 是给搜索引擎识别,在图像无法显示时的替代文本;
title 是关于元素的注释信息,主要是给用户解读。
当鼠标放到文字或是图片上时有 title 文字显示。(因为 IE 不标准)在 IE 浏览器中 alt 起到了 title 的作用,变成文字提示。
在定义 img 对象时,将 alt 和 title 属性写全,可以保证在各种浏览器中都能正常使用。

5. iframe的优缺点?

优点:

  • 解决加载缓慢的第三方内容如图标和广告等的加载问题
  • Security sandbox
  • 并行加载脚本

缺点:

  • iframe会阻塞主页面的Onload事件
  • 即时内容为空,加载也需要时间
  • 没有语意
  • 使用iframe作为子应用问题:1.没有路有记录 2.样式隔离严重

6. href 与 src?

  • href是Hypertext Reference的缩写,表示超文本引用。用来建立当前元素和文档之间的链接。常用的有:link、a
  • src是source的缩写,src的内容是页面必不可少的一部分,是引入。src指向的内容会嵌入到文档中当前标签所在的位置。常用的有:img、script、iframe
  • href与src的区别
    • 1、请求资源类型不同:href 指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的联系。在请求 src 资源时会将其指向的资源下载并应用到文档中,比如 JavaScript 脚本,img 图片;
    • 2、作用结果不同: src用于替换当前元素;href用于在当前文档和引用资源之间建立联系
    • 3、浏览器解析方式不同:当浏览器解析到src ,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等也如此,类似于将所指向资源应用到当前内容。这也是为什么建议把 js 脚本放在底部而不是头部的原因。

7.什么是优雅降级渐进增强?

渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验

优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。

8.HTTP的几种请求方法用途?

  • GET方法
    • 发送一个请求来取得服务器上的某一资源
  • POST方法
    • URL指定的资源提交数据或附加新的数据
  • PUT方法
    • POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有
  • HEAD方法
    • 只请求页面的首部
  • DELETE方法
    • 删除服务器上的某资源
  • OPTIONS方法
    • 它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息
  • TRACE方法
    • TRACE方法被用于激发一个远程的,应用层的请求消息回路
  • CONNECT方法
    • 把请求连接转换到透明的TCP/IP通道

9.HTTP状态码都有哪些?

一、临时响应

100——客户必须继续发出请求
101——客户要求服务器根据请求转换HTTP协议版本
二、成功

200——服务器成功返回网页
201——提示知道新文件的URL
202——接受和处理、但处理未完成
203——返回信息不确定或不完整
204——请求收到,但返回信息为空
205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206——服务器已经完成了部分用户的GET请求
三、重定向

300——请求的资源可在多处得到
301——删除请求数据
302——在其他地址发现了请求数据
303——建议客户访问其他URL或访问方式
304——客户端已经执行了GET,但文件未变化
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除
四、请求错误

400——错误请求,如语法错误
401——请求授权失败
402——保留有效ChargeTo头响应
403——请求不允许
404——请求的网页不存在
405——用户在Request-Line字段定义的方法不允许
406——根据用户发送的Accept拖,请求资源不可访问
407——类似401,用户必须首先在代理服务器上得到授权
408——客户端没有在用户指定的饿时间内完成请求
409——对当前资源状态,请求不能完成
410——服务器上不再有此资源且无进一步的参考地址
411——服务器拒绝用户定义的Content-Length属性请求
412——一个或多个请求头字段在当前请求中错误
413——请求的资源大于服务器允许的大小
414——请求的资源URL长于服务器允许的长度
415——请求资源不支持请求项目格式
416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求
五、服务器错误
500——服务器产生内部错误
501——服务器不支持请求的函数
502——服务器暂时不可用,有时是为了防止发生系统过载
503——服务器超时过载或暂停维修
504——关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长
505——服务器不支持或拒绝支请求头中指定的HTTP版本

10.DOCTYPE (⽂档类型) 的作⽤ ?

DOCTYPE是HTML5中一种标准通用标记语言的文档类型声明,它的目的是 告诉浏览器(解析器)应该以什么样(html或xhtml)的文档类型定义 来解析文档 ,不同的渲染模式会影响浏览器对 CSS 代码甚⾄ JavaScript 脚本的解析。它必须声明在HTML⽂档的第⼀⾏。

浏览器渲染页面的两种模式:

  • CSS1Compat:标准模式(Strick mode) ,默认模式,浏览器使用W3C的标准解析渲染页面。在标准模式中,浏览器以其支持的最高标准呈现页面。
  • BackCompat:怪异模式(混杂模式)(Quick mode) ,浏览器使用自己的怪异模式解析渲染页面。在怪异模式中,页面以一种比较宽松的向后兼容的方式显示。

11.前端需要注意哪些SEO?

  • 合理的title、description,keywords:搜索引擎对着这项的权重逐个减小,title值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title要有所不同;description把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面description有所不同;keywords列举出重要关键词即可
  • 语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页
  • 重要内容HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取
  • 重要内容不要用js输出:爬虫不会执行js获取内容
  • 少用iframe:搜索引擎不会抓取iframe中的内容
  • 非装饰性图片必须加alt
  • 提高网站速度:网站速度是搜索引擎排序的一个重要指标

12.script标签中defer和async的区别 ?

注意: 如果没有defer或async属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。

区别:

  • 执行顺序:多个带async属性的标签,不能保证加载的顺序。多个带有defer属性的标签会按照加载顺序执行
  • 脚本是否并行: async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的即文档加载与js加载同时进行defer属性,js脚本需要等待文档所有元素解析完成后执行 ,DOMContentLoaded事件触发执行之前。

13.常用meta标签有哪些?

meta标签由namecontent属性定义,用来描述网页文档的属性

常用的meta标签:

  • charset:用来描述HTML文档的编码类型
  • keywords:页面关键词
  • description:页面描述
  • refresh:页面重定向和刷新
  • viewport:适配移动端,可以控制视口大小和比例
    • content参数详情:
      • width viewport:宽度(数值/device-width)
      • height viewport:高度(数值/device-height)
      • initial-scale:初始缩放比例
      • maximum-scale:最大缩放比例
      • minimum-scale:最小缩放比例
      • user-scalable:是否允许用户缩放(yes/no)

14.一次完整的HTTP事务是怎么一个过程?

  • 浏览器的地址栏输入URL并按下回车。
  • 浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
  • DNS解析URL对应的IP。
  • 根据IP建立TCP连接(三次握手)。
  • HTTP发起请求。
  • 服务器处理请求,浏览器接收HTTP响应。
  • 渲染页面,构建DOM树。
  • 关闭TCP连接(四次挥手)。

15.HTTP和HTTPS区别?

http:超文本传输协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从www服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更高效,是网络传输减少

https:可以理解为http的安全版,在http下加入SSL层。https协议的主要作用是建立一个安全的信息通道,来确保数组的传输,确保网站的真实性。

区别:

  • Https 协议需要 ca 证书,费用较高。
  • http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议。
  • 使用不同的连接方式,端口也不同,一般而言,http 协议的端口为 80,https 的端口为443
  • http 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、
    身份认证的网络协议,比 http 协议安全。

16.HTTPS是如何实现加密?

HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL协议不仅仅是一套加密传输的协议,更是一件经过艺术家精心设计的艺术品,TLS/SSL中使用了非对称加密,对称加密以及HASH算法

17.img的srcset属性作用?img加载不同图片

响应式页面中经常用到根据屏幕密度设置不同的图片。这时就用到img标签的srcset属性,srcset属性用于设置不同屏幕密度下,img加载图片不同

18.WEB标准以及W3C标准是什么?

  • 标签闭合、标签小写、不乱嵌套、使用外链cssjs、结构行为表现的分离

19.HTML5的离线存储怎么使用?工作原理?

离线存储指的是:在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。

原理: HTML5的离线存储是基于一个新建的.appcache 文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像cookie一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示。

使用方法

  • 创建一个和 html 同名的 manifest 文件,然后在页面头部加入 manifest 属性
  • 在cache .manifest文件中编写需要离线存储的资源
    • CACHE:表示需要离线存储的资源列表,由于包含 manifest 文件的页面将被自动离线存储,所以不需要把页面自身也列出来。
    • NETWORK:表示在它下面列出来的资源只有在在线的情况下才能访问,他们不会被离线存储,所以在离线情况下无法使用这些资源。不过,如果在 CACHE 和 NETWORK
      中有一个相同的资源,那么这个资源还是会被离线存储,也就是说 CACHE 的优先级更高
    • FALLBACK:表示如果访问第一个资源失败,那么就使用第二个资源来替换他,比如上面这个文件表示的就是如果访根目录下任何一个资源失败了,那么就去访问
      offline.html
  • 在离线状态时,操作window.applicationCache进行离线缓存的操作。

20.浏览器是怎么对HTML5的离线储存资源进行管理和加载的呢?

  • 在线的情况下,浏览器发现html头部有manifest属性,它会请求manifest文件,如果是第一次访问app,那么浏览器就会根据manifest文件的内容下载相应的资源并且进行离线存储。如果已经访问过app并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,那么就会重新下载文件中的资源并进行离线存储。
  • 离线的情况下,浏览器就直接使用离线存储的资源。

21.label的作用是什么?

label标签来定义表单控件的关系: 当用户选择label标签时,浏览器会自动将焦点转到和label标签相关的表单控件上

22.Canvas和SVG区别?

Canvas:画布,通过Javascript来绘制2D图形,是逐像索进行染的。其位置发生改变,就会重新进行绘制。

SVG:缩放矢量图形Scalable ecor Grdhics) 是基于可扩展标记语言XML描的2D图的语言。SVG基于XML就意着SG DOM中的元素都是可用的,可以为某个元素附加Javascript事件处理器。在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。

区别:

  • svg绘制出来的每一个图形的元素都是独立的DOM节点,SVG基于XML就意味着SVG DOM中的每个元素都是可用的,可以为某个元素附加Javascript事件处理器,能够方便的绑定事件或用来修改。canvas输出的是一整幅画布
  • svg输出的图形是矢量图形,后期可以修改参数来自由放大缩小,不会是出现锯齿。而canvas输出标量画布,就像一张图片一样,放大会失真或者锯齿

23.head 标签有什么作用,其中什么标签必不可少?

标签用于定义文档的头部,它是所有头部元素的容器。中的元索可以引用脚本、指示浏览器在哪里找到样式表、提供元信息等。 下面这些标签可用在 head 部分: ,,,

24.严格模式与混杂模式如何区分? 它们有何意义?

严格模式:又称为标准模式,指浏览器按照 w3C 标准解析代码;

混杂模式: 又称怪异模式、兼容模式,是指浏览器用自己的方式解析代码。混杂模式通常模拟老式浏览器的行为,以防止老站点无法工作;

区分:

  • 如果文档包含严格的 DOCTYPE,那么它一般以严格模式呈现 (严格 DTD 一一严格模式)
  • 包含过渡 DTD 和 URI 的 DOCTYPE ,也以严格模式呈现,但有过渡 DTD 而没有 URI
    (统一资源标识符,就是声明最后的地址) 会导致页面以混杂模式呈现 (有
    URI 的过渡 DTD --严格模式;没有 URI 的过渡 DTD --混杂模式)
  • DOCTYPE 不存在或形式不正确会导致文档以混杂模式呈现 (DTD不存在或者格式不正确一一混杂模式);
  • HTML5 没有 DTD,因此也就没有严格模式与混杂模式的区别,已经尽可能大的实现了向后兼容(HTML5 没有严格和混杂之分)。

25.浏览器乱码的原因是什么?如何解决?

产生乱码的原因

  • 网页源代码是 gbk 的编码,而内容中的中文字是 utf-8 编码的,这样浏览器打开即会出现 html 乱码,反之也会出现乱码:
  • html 网页编码是 gbk ,而程序从数据库中调出呈现是 utf-8 编码的内容也会造成编码乱码;
  • 浏览器不能自动检测网页编码,造成网页乱码,

解决办法

  • 使用软件编辑HTML网页内容;
  • 如果网页设置编码是 gbk ,而数据库储存数据编码格式是 UTF-8 ,此时需要程序查询数据库数据显示数据前进程序转码:
  • 如果浏览器浏览时候出现网页乱码,在浏览器中找到转换编码的菜单进行转换。

26. 浏览器存储技术 ?

Cookie:是客户端与服务器进行会话使用的一个能够在浏览器本地存储的技术,能存放4kb数据,目的是辨别用户身份

LocalStorage : 在HTML5中新增用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k)

SessionStorage : sessionStorage与localStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对就会被清空。

27.如何优化图像?图像格式的区别?

1.不用图片,尽量用css3代替。比如说要实现修饰效果,如半透明、边框、圆角、阴影、渐变等,在当前主流浏览器中都可以用CSS达成。

2、使用矢量图SVG替代位图。对于绝大多数图案、图标等,矢量图更小,且可缩放而无需生成多套图。现在主流浏览器都支持SVG了,所以可放心使用!

3.、使用恰当的图片格式。我们常见的图片格式有JPEG、GIF、PNG;修饰图片通常更适合用无损压缩的PNG。

GIF基本上除了GIF动画外不要使用。且动画的话,也更建议用video元素和视频格式,或用SVG动画取代。

4、按照HTTP协议设置合理的缓存。

5、使用字体图标webfont、CSS Sprites等。

6、用CSS或JavaScript实现预加载。

7、WebP图片格式能给前端带来的优化。WebP支持无损、有损压缩,动态、静态图片,压缩比率优于GIF、JPEG、JPEG2000、PG等格式,非常适合用于网络等图片传输

图片格式区别:

  • gif:是是一种无损,8位图片格式。具有支持动画,索引透明,压缩等特性。适用于做色彩简单(色调少)的图片,如logo,各种小图标icons等。
  • JPEG格式是一种大小与质量相平衡的压缩图片格式。适用于允许轻微失真的色彩丰富的照片,不适合做色彩简单(色调少)的图片,如logo,各种小图标icons等。
  • png:PNG可以细分为三种格式:PNG8,PNG24,PNG32。后面的数字代表这种PNG格式最多可以索引和存储的颜色值。
    关于透明:PNG8支持索引透明和alpha透明;PNG24不支持透明;而PNG32在24位的PNG基础上增加了8位(256阶)的alpha通道透明;

28.尽可能多的写出浏览器兼容性问题?解决

  • 不同浏览器的标签默认的margin和padding不同
    • 在CSS文件开头,加*{margin: 0; padding: 0;},把所有标签的margin和padding设置为0
  • 块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大
    • 可以将块级元素display设置为inline
  • 设置较小高度标签(一般小于10px),在IE6,IE7, 实际的高度会超出设置的高度,这是因为浏览器给标签设置了一个默认的最小高度
    • 设置{overflow: hidden;},或者设置line-height小于你设置的高度。
  • 在某些浏览器中,图片有默认的间距(所有有文字属性的标签都会有边距,除非两个标签连在一起没有隔开);
    • 使用float为img布局,因为所有标签设置float之后都会变成块级元素,块级元素浮动时会紧挨在一起,没有边距
  • IE9以下浏览器不能使用opacity;
  • {opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);}。

29.HTML全局属性(global attribute)有哪些

  • class:为元素设置类标识
  • data-*: 为元素增加自定义属性
  • draggable: 设置元素是否可拖拽
  • id: 元素id,文档内唯一
  • lang: 元素内容的的语言
  • style: 行内css样式
  • title: 元素相关的建议信息

30.网页验证码是干嘛的,是为了解决什么安全问题

  • 区分用户是计算机还是人的公共全自动程序。可以防止恶意破解密码、刷票、论坛灌水
  • 有效防止黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试

31.为什么利用多个域名来存储网站资源会更有效?

  • CDN缓存更方便
  • 突破浏览器并发限制
  • 节约cookie带宽
  • 节约主域名的连接数,优化页面响应速度
  • 防止不必要的安全问题

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

  • 图片懒加载,在页面上的未可视区域可以添加一个滚动事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。
  • 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
  • 如果图片为css图片,可以使用CSSspriteSVGspriteIconfontBase64等技术。
  • 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
  • 如果图片展示区域小于图片的真实大小,则因在服务器端根据业务需要先行进行图片压缩,图片压缩后大小与展示一致。

33.web开发中会话跟踪的方法有哪些

  • cookie
  • session
  • url重写
  • 隐藏input
  • ip地址

34.title与h1的区别、b与strong的区别、i与em的区别

  • title属性没有明确意义只表示是个标题,H1则表示层次明确的标题,对页面信息的抓取也有很大的影响
  • strong是标明重点内容,有语气加强的含义,使用阅读设备阅读网络时:会重读,而是展示强调内容
  • i内容展示为斜体,em表示强调的文本

35.浏览器的内核有哪些?分别有什么代表的浏览器?

  • IE: trident内核
  • Firefoxgecko内核
  • Safari:webkit内核
  • Opera:以前是presto内核,Opera现已改用Google - ChromeBlink内核
  • Chrome:Blink(基于webkit,Google与Opera Software共同开发)

36.浏览器是如何渲染页面的?

  • 1.解析文档构建DOM树
  • HTML/XHTML/SVG:解析这三种文件后,会生成DOM树(DOM Tree)
  • CSS:解析样式表,生成CSS规则树(CSS Rule Tree)
  • JavaScript:解析脚本,通过DOM API和CSSOM API操作DOM Tree和CSS Rule Tree,与用户进行交互。
  • 2.构建渲染树
  • 解析文档完成后,浏览器引擎会将 CSS Rule Tree 附着到DOM Tree 上,并根据DOM Tree 和 CSS Rule Tree构造 Rendering Tree(渲染树)
  • 3.布局与绘制渲染树
  • 解析position, overflow, z-index等等属性,计算每一个渲染树节点的位置和大小,此过程被称为reflow。最后调用操作系统的Native GUI API完成绘制(repain)。

37.TCP为什么需要三次握手和四次挥手

三次握手是为了建立可靠的数据传输通道,四次挥手则是为了保证等数据完成的被接收完再关闭连接。

38.TCP三次握手

  • 当有客户端需要建立连接的时候就会发送一个确定连接的报文,此报文是同步报文SYN = 1,并且会生成一个随机的序号 seq = x,这是第一次握手
  • 当服务端接收到请求连接报文的时候,会发送一个同步报文确认报文,此报文 SYN = 1,并且 ACK = 1,同时服务端也会随机生成一个 seq = y,并将 ack 设置成 x + 1,回传给客户端,这是第二次握手
  • 当客户端接收到服务端的 ACK 报文后,会回复一个 ACK 确认报文,用于确认确认报文已经收到,此报文 ACK = 1,seq = x + 1, ack = y + 1,这是第三次握手;
  • 这里有个点说明一下:大写的 ACK 表示报文的类型是确认报文,小写的 ack 是报文里面的确认号,这个确认号是上一次握手对方的 seq 值加 1 得到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bU41OHCQ-1686967105034)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml7300\wps2.jpg)]

39.TCP四次挥手

  • 客户端发起 FIN 断开连接的报文,携带随机生成的 seq 值 u,发送给服务端,并且自己处于 FIN-WSIT 状态,这是第一次挥手;
  • 服务端接收到 FIN 报文后,回复一个确认报文,其中 ACK = 1,随机生成一个 seq,以及 ack = u + 1,这是第二次挥手;
  • 当服务端数据发送完了过后,再发送一个 FIN 报文给客户端,通知客户端,服务端准备关闭连接了,此报文 FIN = 1,ACK = 1,ack = u + 1,seq = w,这是第三次挥手;
  • 当客户端收到 FIN 确认报文时再发送一个FIN 的确认报文,其中 ACK = 1,seq = u + 1,ack = w + 1,并进入 TIME-WAIT 状态,当等待 2MSL 后关闭连接,这是第四次挥手。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oh7C8Oyl-1686967105036)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml7300\wps3.jpg)]

40.data-属性的作用?

data-为H5新增的为前端开发者提供自定义的属性,
这些属性集可以通过对象的 dataset 属性获取,
不支持该属性的浏览器可以通过 getAttribute 方法获取 :
需要注意的是:data-之后的以连字符分割的多个单词组成的属性,获取的时候使用驼峰风格。 所有主流浏览器都支持 data-* 属性。
即:当没有合适的属性和元素时,自定义的 data 属性是能够存储页面或 App 的私有的自定义数据

41.HTML5新特性?

1.语义化标签

  • header:定义文档的页眉( 头部)

  • nav: 定义导航链接的部分

  • footer: 定义文档或节的页脚 (底部)

  • article: 定义文章内容

  • section: 定义文档中的节 (section、区段)

  • aside: 定义其所处内容之外的内容 (侧边)

2.媒体标签

  • audio:音频
    • 属性:
      • src音频链接
      • controls控制面板
      • autoplay自动播放
      • loop='true’循环播放
  • video:视频
    • 属性:
      • poster: 指定视频还没有完全下载完毕,或者用户还没有点击播放前显示的封面。默认显示当前视频文件的第一针画面,当然通过poster也可以自己指定
      • controls:控制面板
      • width,height
  • source标签:因为浏览器对视频格式支持程度不一样,为了能够兼容不同的浏览器,可以通过source来指定视频源。

3.表单

  • 表单类型:
    • email:能够验证当前输入的邮箱地址是否合法
    • url :验证URL
    • number: 只能输入数字,其他输入不了,而且自带上下增大减小箭头,max属性可以设置为最大值,min可以设置为最小值,value为默认值。
    • search : 输入框后面会给提供一个小叉,可以删除输入的内容,更加人性化。
    • range : 可以提供给一个范围,其中可以设置max和min以及value,其中
      value属性可以设置为默认值
    • color : 提供了一个颜色拾取器
    • time : 时分秒
    • date : 日期选择年月日
    • datatime: 时间和日期(目前只有Safari支持)
    • datatime-local: 日期时间控件
    • week : 周控件
    • month: 月控件
  • 表单属性:
    • placeholder: 提示信息
    • autofocus : 自动获取焦点
    • autocomplete=“on” 或者 autocomplete=“off”使用这个属性需要有两个前提:
      • 表单必须提交过
      • 必须有name属性
    • required: 要求输入框不能为空,必须有值才能够提交
    • pattern=””里面写入想要的正则模式
    • multiple: 可以选择多个文件或者多个邮箱
    • form=form表单的ID!
  • 表单事件:
    • oninput 每当input里的输入框内容发生变化都会触发此事件。
    • oninvalid 当验证不通过时触发此事件。

4.进度条,度量器

  • progress标签:用来表示任务的进度 (IE、Safari不支持) ,max用来表示任务的进度,value表示已完成多少
  • meter属性: 用来显示剩余容量或剩余库存 (IE、Safari不支持)
    • high/low:规定被视作高/低的范围
    • max/min: 规定最大/小值
    • value: 规定当前度量值

5.DOM查询操作

  • document.querySelector()
  • document.querySelectorAll()

6.Web存储

  • localStorage和sessionStorage

7.其他

  • 拖放:拖放是一种常见的特性,即抓取对象以后拖到另一个位置。设置元素可拖放
  • canvas和svg
  • websocket,webwork
  • 地理定位
  • data-自定义属性

42.web worker的理解?如何创建?

在 HTML 页面中,如果在执行脚本时,页面的状态是不可相应的,直到脚本执行完成后,页面才变成可相应。web worker 是运行在后台的 js,独立于其他脚本,不会影响页面的性能。 并且通过 postMessage 将结果回传到主线程。这样在进行复杂操作的时候,就不会阻塞主线程了。

创建:

  • 检测浏览器对于 web worker 的支持性
  • 创建 web worker 文件 (js,回传函数等)
  • 创建 web worker 对象

43.说下HTML5 drag API

dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发。
darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。
dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。
dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。
drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。
dragend:事件主体是被拖放元素,在整个拖放操作结束时触发。

44.Http 短轮询、长轮询

轮询:是由由客户端每隔一段时间(如每隔5s) 向服务器发出HTTP请求,服务端接收到请求后向客户端返回最新的数据。

客户端轮循:短轮询,长轮询

  • 短轮询:一般是由客户端每隔一段时间(如每隔5s) 向服务器发起一次普通 HTTP 请求 。服务端查询当前接口是否有数据更新,若有数据更新则向客户端返回最新数据,若无则提示客户端无数据更新
  • 长轮询: 一般是由客户端向服务端发出一个设置较长网络超时时间的 HTTP 请求,并在Http连接超时前,不主动断开连接;待客户端超时或有数据返回后,再次建立一个同样的Http请求,重复以上过程

45.canvas绘图基础(直线,三角形,矩形,圆形)

<canvas id=“myCanvas” width=200 height=100 ></canvas>
  • 1
  • id 是canvas元素的标识;
  • height,width规定画布大小

直线

beginPath()方法,指示开始绘图路径: ctx.beginPath();
moveTo()方法将坐标移至直线起点: ctx.moveTo(x,y);
lineTo()方法绘制直线: ctx.lineTo(x,y);
stroke()方法,绘制图形的边界轮廓: ctx.stroke();
closePath()方法,指示闭合绘图路径: ctx.closePath()

    var mycanvas=document.getElementById("canvas");
    var ctx=mycanvas.getContext("2d");
	ctx.beginPath();
	ctx.moveTo(100,100);//移动到绘制点
	ctx.lineTo(200,200);
	ctx.strokeStyle="#000000"; //指定描边颜色
	ctx.stroke();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三角形

	var mycanvas=document.getElementById("canvas");
    var ctx=mycanvas.getContext("2d");
	ctx.beginPath();
	ctx.moveTo(100,200);
	ctx.lineTo(400,200);
	ctx.lineTo(250,400);
	ctx.closePath();//闭合绘图
	ctx.strokeStyle="#000000";
	ctx.stroke();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

矩形

绘制矩形:rect(x,y,width,height);

绘制矩形边框:strokeRect(x, y, width, height);

绘制填充矩形:fillRect(x, y, width, height);

擦除指定矩形区域:clearRect(x, y, width, height);

	var mycanvas=document.getElementById("canvas");
	var ctx=mycanvas.getContext("2d");
 
	//rect()函数调用
	ctx.beginPath();
	ctx.rect(20,20,100,50);
	ctx.stroke();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

圆形:arc(centerx,centery,radius,startAngle,endAngle,antiClockwise);

  • centerx,centery 圆弧中心点坐标
  • Radius 半径
  • startAngle 起始弧度
  • endAngle 终止弧度
  • antiClockwise 是否按逆时针方向绘图, 是一个可选参数,默认为false(即顺时针方向绘图)
    弧度 = 角度* ( Math.PI / 180 )
	var mycanvas=document.getElementById("canvas");
	var ctx=mycanvas.getContext("2d");
	//arc()函数调用
	ctx.beginPath();
	ctx.arc(100,150,70,0,90*Math.PI/180,true);
	ctx.stroke();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

46.TCP和HTTP区别?

  • TCP对应于传输层,HTTP对应于应用层,从本质上来说,二者没有可比性。

  • Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接

  • TCP是底层协议,定义的是数据传输和连接方式的规范。

    HTTP是应用层协议,定义的是传输数据的内容的规范。

    HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP就一定支持TCP

二、CSS 篇

1. 介绍一下 CSS 的盒子模型?

margin(外边距)- 清除边框外的区域,外边距是透明的。
border(边框)- 围绕在内边距和内容外的边框。
padding(内边距)- 清除内容周围的区域,内边距是透明的。
content(内容)- 盒子的内容,显示文本和图像。

W3C的标准盒模型:在标准的盒子模型中,width指content部分的宽度

IE的盒模型:在IE盒子模型中,width表示content+padding+border这三个部分的宽度

  • 如何开启不同盒子模型
    • box-sizing:content-box; 标准盒子模型
    • box-sizing:border-box; IE盒子模型

2.css选择器?

  • id选择器(#box),选择id为box的元素
  • 类选择器(.one),选择类名为one的所有元素
  • 标签选择器(div),选择标签为div的所有元素
  • 后代选择器(#box div),选择id为box元素内部所有的div元素
  • 子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素
  • 相邻同胞选择器(.one+.two),选择紧接在.one之后的所有.two元素
  • 群组选择器(div,p),选择div、p的所有元素
  • 伪类选择器
  • 属性选择器

3. css 选择器优先级?

!important > 行内样式(比重1000)> ID 选择器(比重100) > 类选择器(比重10) > 标签(比重1) > 通配符 > 继承 > 浏览器默认属性

4.css中可继承属性?

  • 字体系列属性
    • font-family:字体系列
    • font-weight:字体粗细
    • font-size:字体大小
    • font-style:字体风格
  • 文本系列属性
    • text-indent:文本缩进
    • text-align:文本水平对齐
    • line-height:行高
    • color:文字颜色
  • 元素可见性:visibility
  • 列表布局属性:list-style
  • 光标属性:cursor

5. 垂直居中几种方式?

  • 将显示方式设置为表格,display:table-cell,同时设置vertial-align:middle
  • 使用flex布局,设置为align-item:center
  • 绝对定位中设置bottom:0,top:0,并设置margin:auto
  • 绝对定位中固定高度时设置top:50%,margin-top值为高度一半的负值
  • 文本垂直居中设置line-heightheight

6. 简明说一下 CSS link 与 @import 的区别和用法?

  • link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
  • 页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
  • import是CSS2.1 提出的,只在IE5以上才能被识别,而link是XHTML标签,无兼容问题

7. rgba和opacity的透明效果有什么不同?

  • Rgba即可以指定元素颜色也可以指定透明度,opacity只能控制元素透明度不能设置颜色
  • Rgba透明度是基于实际颜色而opacity是针对元素本身透明度设置,在使用rgba是可以实现元素不同部位透明度不同,而opacity使元素透明度一致
  • 支持rgba的浏览器比支持opacity的更普遍但是在低版本的ie中rgba不被支持而支持opacity

8.display的属性值及作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JAbGv3HB-1686967105037)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683804216661.png)]

9.display的block,inline和inline-block区别?

block: 会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;

inline: 元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;

inline-block: 将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内。

10. display:none和visibility:hidden的区别?

display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。
visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。

11. position的值, relative和absolute分别是相对于谁进行定位的?

relative:相对定位,相对于自己本身在正常文档流中的位置进行定位。
absolute:生成绝对定位,相对于最近一级定位不为static的父元素进行定位。最终找到body
fixed: (老版本IE不支持)生成绝对定位,相对于浏览器窗口或者frame进行定位。
static:默认值,没有定位,元素出现在正常的文档流中。
sticky:生成粘性定位的元素,容器的位置根据正常文档流计算得出。

12.隐藏元素的方法有哪些?

display: none: 渲染树不会包含该染对象,因此该元素不会在页面中占据位置,也不会响应绑定的监听事件。

visibility: hidden: 元素在页面中仍占据空间,但是不会响应绑定的监听事件

opacity: 0: 将元素的透明度设置为 0,以此来实现元素的隐藏。元素在页面中仍然占据空间,并且能够响应元素绑定的监听事件

position: absolute: 通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏

z-index: 负值: 来使其他元素遍盖住该元素,以此来实现隐藏

transform: scale(0,0): 将元索缩放为 0,来实现元素的隐藏。

13.transition和animation区别?

  1. 触发方式不同:transition 通过 CSS 属性值的变化来触发动画效果,而 animation 则需要通过设置关键帧(keyframes)来指定动画序列。
  2. 控制方式不同:transition 只能控制开始和结束状态之间的过渡动画,而 animation 可以指定多个关键帧,控制元素动画的每一个阶段,包括动画开始、中间和结束的时刻、变换状态以及持续时间等。
  3. 耗费资源不同:相对来说,animation 消耗的浏览器资源更多,因为它需要计算多个关键帧之间的动画效果,而 transition 只需在两种状态之间进行简单的计算即可。
  4. 兼容性不同:transition 相对来说更加兼容不同的浏览器,而 animation 在某些旧版浏览器上可能无法正常工作。

14.伪元素和伪类区别?

伪元素:是创造文档树之外的对象。例如文档不能提供访问元素内容第一字或者第一行的机制。伪元素还提供一些在源文档中不存在的内容分配样式,例如:before和:after能够访问产生的内容。伪元素的内容实际上和普通DOM元素是相同的,但是它本身只是基于元素的抽象,并不存在于文档中,所以叫伪元素。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mND9y0Cq-1686967105038)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683805298891.png)]

伪类:是基于元素的特征而不是他们的id、class、属性或者内容。一般来说,元素的特征是不可以从DOM树上推断得到的,而且其是动态的,当用户和DOM进行交互的时候,元素可以获得或者失去一个伪类。(这里有一个例外,就是:first-child和:lang是可以从DOM树中推断出来的。)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0PrLEaC2-1686967105039)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683805345353.png)]

两者的异同

相同:

  • 伪类和伪元素都不出现在源文件和文档树中。也就是说在html源文件中是看不到伪类和伪元素的。

差异:

  • 伪类其实就是基于普通DOM元素而产生的不同状态,他是DOM元素的某一特征。伪元素能够创建在DOM树中不存在的抽象对象,而且这些抽象对象是能够访问到的。

15.对requestAnimationframe的理解

HTML5 提供一个专门用于请求动画的API

语法:

  • window.requestAnimationFrame(callback); 其中,callback是下一次重绘之前更新动画顿所调用的函数(即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp参数,它表示requestAnimationFrame()开始去执行回调函数的时刻。该方法属于宏任务,所以会在执行完微任务之后再去执行。

取消动画:

  • 使用cancelAnimationFrame()来取消执行动画,该方法接收-个参数–requestAnimationFrame默认返回的id,只需要传入这个id就可以取消动画了。

优势:

  • CPU节能
  • 函数节流
  • 减少DOM操作

16.li 与 li 之间有看不见的空白间隔是什么原因引起的? 如何解决?

浏览器会把inline内联元素间的空白字符(空格、换行、Tab等) 染成一个空格。为了美观,通常是一个

  • 放在一行,这导致
  • 换行后产生换行字符,它变成一个空格,占用了一个字符的宽度。
  • 解决:

    • 设置float:left。不足: 有些容器是不能设置浮动,如左右切换的焦点图等.
    • 将所有
    • 写在同一行。不足: 代码不美观。
    • 将内的字符尺寸直接设为0,即font-size:0。不足:
      • 中的其他字符尺寸也被设为0,需要额外重新设定其他字符尺寸,且在Safari浏览器依然会出现空白间隔。
    • 消除
      • 的字符间隔letter-spacing:-8px,不足: 这也设置了
      • 内的字符间隔,因此需要将
      • 内的字符间隔设为默认letter-spacing:normal。

17.CSS3新特性

  • 新增各种css选择器(:not(.input):所有class不是’input’的节点):属性选择器,伪类选择器,伪元素选择器,基本选择器
  • 三个边框属性
    • border-radius:创建圆角边框
    • border-shadow:为元素添加阴影
    • border-image:使用图片来绘制边框
  • 背景
    • background-clip:确定背景画区
    • background-origin:设置是从border-box,padding-box,content-box那个盒子的左上角开始对其
    • background-size:调整背景图片大小
    • background-break:元素可以被分成几个独立的盒子
  • 文字
    • word-wrap:normal|break-word 使用浏览器默认的换行|允许在单词内换行
    • text-overflow:设置或检索当前行超过指定容器的边界如何显示,属性由两个值
      • clip:修剪文本
      • ellipsis:显示省略符号来代表被修剪的文本
    • text-shadow:可向文本应用阴影。能够规定水平阴影,垂直阴影,模糊距离,以及阴影颜色
    • text-decoration:CSS3里面开始支持对文字的更深层次的渲染,具体有三个属性可以提供
      • text-fill-color:设置文字内部填充颜色
      • text-stroke-color:设置文字边界填充颜色
      • text-stroke-width:设置文字边界宽度
  • 颜色(新增颜色表示方式rgba与hsla)
    • rgba分为两部分,rgb为颜色值,a为透明度
    • hsla分为四部分,h为色相,s为饱和度,l为亮度,a为透明度
  • transition过渡,transform转换,animation动画
  • flex弹性布局,Grid栅格布局
  • 媒体查询

18.创建图片格式(简述),区别?

  • BMP:是无损的、既支持索引色也支持直接色的点阵图
  • GIF:是无损的、采用索引色的点阵图。采用LZW压缩算法进行编码
  • JPEG:是有损的、采用直接色的点阵图。JPEG的图片的优点是采用了直接色,得益于更丰富的色彩
  • PNG-8:是无损的、使用索引色的点阵图。
  • PNG-24:是无损的、使用直接色的点阵图。
  • SVG:是无损的矢量图。SVG是矢量图意味着SVG图片由直线和曲线以及绘制它们的方法组成
  • WebP:是谷歌开发的一种新图片格式,WebP是同时支持有损和无损压缩的、使用直接色的点阵图。

19. 画一条0.5px的直线?

考查的是css3的transform

height: 1px;
transform: scale(0.5);
  • 1
  • 2

20. calc, support, media各自的含义及用法?

  • @support 主要是用于检测浏览器是否支持CSS的某个属性,其实就是条件判断,如果支持某个属性,你可以写一套样式,如果不支持某个属性,你也可以提供另外一套样式作为替补。
  • calc() 函数用于动态计算长度值。 calc()函数支持 “+”, “-”, “*”, “/” 运算;
  • @media 查询,你可以针对不同的媒体类型定义不同的样式。

21.px和em,rem区别?

px:绝对长度单位,像素px是相对于显示器屏幕分辨率来说的
em:相对长度单位,相对于当前对象内文本的font-size,em的值并不是固定的,em会继承父级元素的font-size(参考物是父元素的font-size)
rem:相对于html根元素的font-size

22. 1rem、1em、1vh、1px,vmin,vmax各自代表的含义?

  • rem
    rem是全部的长度都相对于根元素元素。通常做法是给html元素设置一个字体大小,然后其他元素的长度单位就为rem。
  • em
    子元素字体大小的em是相对于父元素字体大小
    元素的width/height/padding/margin用em的话是相对于该元素的font-size
  • vw/vh
    全称是 Viewport Width 和 Viewport Height,视窗的宽度和高度,相当于 屏幕宽度和高度的 1%,不过,处理宽度的时候%单位更合适,处理高度的 话 vh 单位更好。
  • px
    px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。
    一般电脑的分辨率有{19201024}等不同的分辨率
    1920
    1024 前者是屏幕宽度总共有1920个像素,后者则是高度为1024个像素
  • vmin/vmax: 取视窗高度和宽度的最小值作为基准/取视窗高度和宽度的最大值作为基准。
    • 如果窗口高度1080,宽度1920那么。 1vmin=1080px/100=10.8px 1vmax=1920px/100=19.2px

23. CSS画一个三角形?

这属于简单的css考查,平时在用组件库的同时,也别忘了原生的css

.a {
    width: 0;
    height: 0;
    border-width: 100px;
    border-style: solid;
    border-color: transparent #0099CC transparent transparent;
    transform: rotate(90deg); /*顺时针旋转90°*/
}
<div class="a"></div>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

24.元素水平垂直居中

  • 利用定位+margin:auto
  • 利用定位+margin:负值
  • 利用定位+transform
  • table布局
  • flex布局
  • grid布局

25.响应式布局原理

  1. 什么是响应式: 一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台,屏幕尺寸,屏幕定向等)进行相应的响应和调整
  2. 基本原理: 通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport.
  3. 实现方式
    • 媒体查询
    • 百分比布局
    • vw/vh
    • rem

26.CSS定位方式?

static:元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。

relative:元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。

absolute:元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。

fixed:元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身。

27.css sprite(雪碧图,精灵图)是什么,有什么优缺点?

CSSSprites(精灵图),将一个页面涉及到的所有图片都包含到一张大图中去,然后利用CSS的 background-image,background-repeat,background-position属性的组合进行背景定位。

优点:

  • 减少HTTP请求,极大提高页面加载速度
  • 增加图片信息重复度,提高压缩比,减少图片大小
  • 更换风格方便,只需要在一张或几张图片上修改颜色或样式即可

缺点:

  • 图片合并麻烦
  • 维护麻烦

28.设备像素、css像素、设备独立像素、dpr、ppi 之间的区别?

设备像素:又称为物理像素, 指设备能控制显示的最小物理单位,不一定是一个小正方形区块,也没有标准的宽高,只是用于显示丰富色彩的一个“点”而已

css像素: 适用于web编程,在 CSS 中以 px 为后缀,是一个长度单位 。css中长度分为两类:绝对单位和相对单位,px属于相对单位

设备独立像素: 与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念 。我们常说的分辨率,不严谨来讲是指的设备独立像素。在javascript中我们可以通过 window.screen.width/ window.screen.height 来查看

dpr:设备像素比, 代表设备独立像素到设备像素的转换关系

ppi:像素密度, 表示每英寸所包含的像素点数目

29.margin 和 padding 的使用场景

需要在border外侧添加空白,且空白处不需要背景 (色)时,使用 margin;

需要在border内测添加空白,且空白处需要背景(色) 时,使用 padding。

30.对line-height的理解,赋值方式

概念:

  • line-height 属性设置行间的距离(行高),说的直白一点,就是设置两段段文本之间的距离如果我们把一段文本的line-height设置为父容器的高度就可以实现文本垂直居中了。

原理:

  • 我们可以理解为将div分为三份,分别为上边距,内容,下边距。举例:div高度100px,字体为16px,那么上下边距计算为(100px-16px)/2

赋值方式:

  • 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算自身的行高
  • 纯数字:会把比例传递给后代。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px
  • 百分比:将计算后的值传递给后代

31.谈谈你对BFC的理解?触发条件?应用场景?

概念: BFC即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则。BFC目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素

触发条件:

  • 根元素,即HTML元素
  • 浮动元素:float值为left、right
  • overflow值不为 visible,为 auto、scroll、hidden
  • display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
  • position的值为absolute或fixed

应用场景:

  • 防止margin重叠
  • 清楚内部浮动
  • 自适应多栏布局

32.如何实现两栏布局,右侧自适应?三栏布局中间自适应?

两栏布局

  • 使用float左浮动左边栏,右边使用margin-left撑出左边栏宽度大小,为父元素添加BFC通过overflow:hidden开启。
  • flex布局

三栏布局

  • 下面三个方法原理与两栏布局第一个方法相同
    • 两边使用 float,中间使用 margin
    • 两边使用 absolute,中间使用 margin
    • 两边使用 float 和负 margin
  • flex布局
  • display: table 实现
    • 通过 display: table设置为表格,设置 table-layout: fixed`表示列宽自身宽度决定,而不是自动计算。
    • 内层的左中右通过 display: table-cell设置为表格单元。
    • 左右设置固定宽度,中间设置 width: 100% 填充剩下的宽度
  • grid网格布局

33.说说flexbox(弹性盒布局模型),以及适用场景?

理解:flex布局意为“弹性布局”,可以 简便、完整、响应式地实现各种页面布局 。 容器中默认存在两条轴,主轴和交叉轴,呈90度关系。项目默认沿主轴排列,通过flex-direction来决定主轴的方向

属性:

  • flex-direction 决定主轴的方向
  • flex-wrap 决定容器内项目是否可换行
    • wrap,换行
  • justify-content 项目在主轴上的对齐方式
    • flex-start(默认值):左对齐
    • flex-end:右对齐
    • center:居中
    • space-between:两端对齐,项目之间的间隔都相等
    • space-around:两个项目两侧间隔相等
  • align-items 项目在交叉轴上如何对齐
    • flex-start:交叉轴的起点对齐
    • flex-end:交叉轴的终点对齐
    • center:交叉轴的中点对齐 垂直居中
    • baseline: 项目的第一行文字的基线对齐
    • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
  • align-content

34.介绍一下grid网格布局

理解:Grid 布局即网格布局,是一个二维的布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列

容器属性:

  • display:grid该容器是一个块级元素/inline-grid该容器是一个行内元素
  • grid-template-columns 属性,grid-template-rows 属性:
    • 设置列宽,行高几行几列。如果重复宽高可通过repeat(3,200px)表示3行列,200px宽高
  • grid-row-gap 属性, grid-column-gap 属性, grid-gap 属性
    • 设置行列间距,grid-gap是两者简写
  • grid-template-areas 属性:用于定义区域
  • grid-auto-flow 属性: 划分网格以后,容器的子元素会按照顺序 , 顺序就是由grid-auto-flow决定

项目属性:

  • grid-column-start 属性、grid-column-end 属性、grid-row-start 属性以及grid-row-end 属性: 指定网格项目所在的四个边框,分别定位在哪根网格线,从而指定项目的位置
  • grid-area 属性: 属性指定项目放在哪一个区域 。由grid-template-areas 属性划分区域
  • justify-self 属性、align-self 属性以及 place-self 属性

35.CSS3动画有哪些?

  • transition 实现渐变动画

  • transform 转变动画

  • animation 实现自定义动画

36.怎么理解回流跟重绘?什么场景下会触发?

  • 回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
  • 重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制

触发条件:

  • 回流:
    • 添加或删除可见的DOM元素
    • 元素的位置发生变化
    • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
    • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
    • 页面一开始渲染的时候(这避免不了)
    • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
  • 重绘------ 触发回流一定会触发重绘
    • 颜色的修改
    • 文本方向的修改
    • 阴影的修改

37.如果要做优化,CSS提高性能的方法有哪些?

  • 内联首屏关键CSS
  • 避免使用css表达式
  • 异步加载CSS
  • 资源压缩
  • 合理使用选择器
  • 减少使用昂贵的属性 如 box-shadow/border-radius/filter/透明度/:nth-child
  • 不要使用@import

38.如何实现单行/多行文本溢出的省略样式?

单行文本溢出

  • white-space:设置文字在一行显示,不能换行
  • overflow:文字长度超出限定宽度,则隐藏超出的内容
  • text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本
    • clip:当对象内文本溢出部分裁切掉
    • ellipsis:当对象内文本溢出时显示省略标记(…)
    • text-overflow只有在设置了overflow:hiddenwhite-space:nowrap才能够生效的

多行文本溢出省略

  • 基于高度截断 – 伪元素 + 定位
    • position: relative:为伪元素绝对定位
    • overflow: hidden:文本溢出限定的宽度就隐藏内容)
    • line-height: 20px:结合元素高度,高度固定的情况下,设定行高, 控制显示行数
    • height: 40px:设定当前元素高度
    • ::after {} :设置省略号样式 – 设置伪元素
    • position: absolute:给省略号绝对定位
    • content:“…”
  • 基于行数截断 – 纯css
    • -webkit-line-clamp: 2:用来限制在一个块元素显示的文本的行数,为了实现该效果,它需要组合其他的WebKit属性)
    • display: -webkit-box:和-webkit-line-clamp结合使用,将对象作为弹性伸缩盒子模型显示
    • -webkit-box-orient: vertical:和-webkit-line-clamp结合使用 ,设置或检索伸缩盒对象的子元素的排列方式
    • overflow: hidden:文本溢出限定的宽度就隐藏内容
    • text-overflow: ellipsis:多行文本的情况下,用省略号“…”隐藏溢出范围的文本

39.让Chrome支持小于12px 的文字方式有哪些?区别?

Chrome 中文版浏览器会默认设定页面的最小字号是12px,英文版没有限制 。

解决方案:

  • zoom : “变焦”,可以改变页面上元素的尺寸,属于真实尺寸
  • -webkit-transform:scale(): 针对chrome浏览器,加webkit前缀,用transform:scale()这个属性进行放缩
  • -webkit-text-size-adjust:none: 该属性用来设定文字大小是否根据设备(浏览器)来自动调整显示大小

区别:

  • Zoom 非标属性,有兼容问题,缩放会改变了元素占据的空间大小,触发重排
  • -webkit-transform:scale() 大部分现代浏览器支持,并且对英文、数字、中文也能够生效,缩放不会改变了元素占据的空间大小,页面布局不会发生变化
  • -webkit-text-size-adjust对谷歌浏览器有版本要求,在27之后,就取消了该属性的支持,并且只对英文、数字生效

40.说说对Css预编语言(sass,less)的理解?有哪些区别?

理解: 扩充了 Css 语言,增加了诸如变量、混合(mixin)、函数等功能,让 Css 更易维护、方便 。 本质上,预处理是Css的超集 。 包含一套自定义的语法及一个解析器,根据这些语法定义自己的样式规则,这些规则最终会通过解析器,编译生成对应的 Css 文件

有哪些:sass,less,stylus

比较less和sass:

  • 相同点:
    • 首先sass和less都是css的预编译处理语言,它们引入了mixins,参数,嵌套规则,运算,颜色,名字空间,作用域,JavaScript赋值等加快了css开发效率,当然这两者都可以配合gulp和grunt等前端构建工具使用
  • 区别:
    • less是基于JavaScript的在客户端处理 所以安装的时候用npm
    • sass是基于ruby所以在服务器处理
  • less优缺点
    • 优点: less 简单,易上手;属于css的基础拓展;less更适合静态界面写样式时
    • 缺点: JavaScript引擎需要额外的时间来处理代码然后输出修改过的CSS到浏览器
  • sass优缺点
    • 优点: 功能强大,更加丰富的拓展sass适合游戏或者其他做效果时需要逻辑来更换不同样式
    • 缺点: 复杂对于新手比较不友好

41.什么是FOUC?如何避免?

FOUC: 即无样式内容闪烁,也可以称为文档样式短暂失效,主要就是指HTML已加载而样式表并未加载,此后样式表再加载而产生的闪烁现象。

如何避免:

  • 样式表前置 : 根据浏览器渲染的顺序,将CSS在中引入或者嵌入
  • 尽量使用link避免使用@import

42.清除浮动的方式,各自优缺点?

  • 额外标签法: 给谁清除浮动,就在其后额外添加一个空白标签

    • 优点: 通俗易懂,书写方便。(不推荐使用)
    • 缺点: 添加许多无意义的标签,结构化比较差。
  • 父级添加overflow方法: 可以通过触发BFC的方式,实现清楚浮动效果。

    • 优点: 简单、代码少、浏览器支持好
  • 缺点: 内容增多时候容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素。不能和position配合使用,因为超出的尺寸的会被隐藏。

  • 使用after伪元素清除浮动: :after方式为空元素的升级版,好处是不用单独加标签了。

    • 优点: 符合闭合浮动思想,结构语义化正确,不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等)
    • 缺点: 由于IE6-7不支持

43.在网页中的应该使用奇数还是偶数的字体?为什么呢?

  • 偶数字号相对更容易和 web 设计的其他部分构成比例关系

44.如果需要手动写动画,你认为最小时间间隔是多久,为什么?(阿里)

  • 多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms

45.base64的原理及优缺点?

  • 优点可以加密,减少了HTTTP请求
  • 缺点是需要消耗CPU进行编解码

46.流体布局,圣杯布局,双飞翼布局?

圣杯布局和双飞翼布局的区别:

  • 相同点
    • 两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局,并且中间部分在HTML代码中要写在前边,这样它就会被优先加载渲染。
  • 不同点
    • 主要的不同之处就是在解决中间部分被挡住的问题时,采取的解决办法不一样。圣杯布局是在父元素上设置了padding-left和padding-right,在给左右两边的内容设置position为relative,通过左移和右移来使得左右两边的内容得以很好的展现,而双飞翼布局则是在中间这个div的外层又套了一个div来放置内容,在给这个中间的div设置margin-left和margin-right 。

47.postcss的作用

PostCSS是一个使用JS插件转换CSS的工具。这些插件可以支持变量和混合、transpile未来CSS语法、内联图像等。

作用:

  • 支持未来的css: 使用cssnext书写未来的css(postcss-cssnext plugin)
  • 编译速度大大提升。PostCSS 声称比预处理器快 3-30 倍。
  • 丰富的插件系统,解放你的双手。
  • css模块化,将作用域限制于组件内,避免了全局作用域的问题,再也不用担心样式名重复了

Postcss属于css后处理器,动态编译css,也就是说,在运行的时候进行编译。

48.css有个content属性吗?有什么作用?有什么应用?

css的content属性专门应用在 before/after伪元素上,用于来插入生成内容。最常见的应用是利用伪类清除浮动。

49.水平居中方法

  • 元素为行内元素,设置父元素text-align:center
  • 如果元素宽度固定,可以设置左右marginauto;
  • 绝对定位和移动: absolute + transform
  • 使用flex-box布局,指定justify-content属性为center
  • display设置为tabel-ceil

50.详细说一说css3的animation,transition

  • animation
    • css3的animation是css3新增的动画属性,这个css3动画的每一帧是通过@keyframes来声明的,keyframes声明了动画的名称,通过fromto或者是百分比来定义动画过程
    • 每一帧动画元素的状态,通过animation-name来引用这个动画,同时css3动画也可以定义动画运行的时长、动画开始时间、动画播放方向、动画循环次数、动画播放的方式,
    • 这些相关的动画子属性有:
      • animation-name定义动画名
      • animation-duration定义动画播放的时长
      • animation-delay定义动画延迟播放的时间
      • animation-direction定义 动画的播放方向
      • animation-iteration-count定义播放次数
      • animation-fill-mode定义动画播放之后的状态
      • animation-play-state定义播放状态,如暂停运行等
      • animation-timing-function定义播放的方式,如恒速播放、减速播放等。
  • transition
    • transition-property :规定设置过渡效果的css属性名称
    • transition-duration :规定完成过渡效果需要多少秒或毫秒
    • transition-timing-function :指定过渡函数,规定速度效果的速度曲线
    • transition-delay :指定开始出现的延迟时间

51.什么是css Hack?常见Hack

描述:是通过在CSS样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(什么样的浏览器识别什么样的符号是有标准的,CSS hack就是让你记住这个标准),以达到应用不同的CSS样式的目的。

常见hack:

  • 属性级Hack:比如IE6能识别下划线“”和星号“*”,IE7能识别星号“*”,但不能识别下划线””,而firefox两个都不能认识。
  • 选择符级Hack:比如IE6能识别html .class{},IE7能识别+html .class{}或者*:first-child+html .class{}。
  • IE条件注释Hack:IE条件注释是微软IE5开始就提供的一种非标准逻辑语句。

52.浏览器是怎样解析CSS选择器的?

  • 浏览器解析 CSS 选择器的方式是从右到左

53.抽离样式模块怎么写,说出思路

  • CSS可以拆分成2部分:公共CSS 和 业务CSS:
    • 网站的配色,字体,交互提取出为公共CSS。这部分CSS命名不应涉及具体的业务
    • 对于业务CSS,需要有统一的命名,使用公用的前缀。可以参考面向对象的CSS

54.元素竖向的百分比设定是相对于容器的高度吗?

不是

无论是竖向还是横向的百分比设定都是相对于容器的宽度。我们可以通过margin和padding来进行验证

55.全屏滚动的原理是什么? 用到了CSS的那些属性?

  • 原理类似图片轮播原理,超出隐藏部分,滚动时显示
  • 可能用到的CSS属性:overflow:hidden; transform:translate(100%, 100%); display:none;

56.设置元素浮动后,该元素的 display 值会如何变化

设置元素浮动后,该元素的 display 值自动变成 block

57.display:inline-block 什么时候会显示间隙?

  • 相邻的 inline-block 元素之间有换行或空格分隔的情况下会产生间距
  • inline-block 水平元素设置为 inline-block 也会有水平间距
  • 可以借助 vertical-align:top; 消除垂直间隙
  • 可以在父级加 font-size:0; 在子元素里设置需要的字体大小,消除垂直间隙
  • li 标签写到同一行可以消除垂直间隙,但代码可读性差

58.pageX,clientX,screenX,offsetX区别?

pageX/Y: 对于整个页面来说,包括了被卷去的body部分的长度

clientX/Y: 点击位置距离当前body可视区域的x,y坐标

screenX/Y: 点击位置距离当前电脑屏幕的x,y坐标

offsetX/Y: 相对于带有定位的父盒子的x,y坐标

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXHtNM4t-1686967105041)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683882788135.png)]

59.如何对不同IE版本浏览器做兼容测试?

使用工具切换IE版本,然后在IE浏览器运行测试

60.border- radius详解

在开发中我们经常通过正方形设置border- radius:50%来实现圆

border-radius参数选择:

  • border-radius:10px;将创建四个大小一样的圆角
  • border-radius:10px 15px 10px 15px; 四个值分别表示左上角、右上角、右下角、左下角
  • border-radius:10px 15px; 第一个值表示左上角、右下角;第二个值表示右上角、左下角
  • border-radius:10px 15px 5px; 第一个值表示左上角;第二个值表示右上角、左下角;第三个值表示右下角。

61.让页面里的字体变清晰,变细用CSS怎么做?

-webkit-font-smoothing: antialiased;

63.CSS3渐变?

CSS3 定义了两种类型的渐变(gradients):

  • 线性渐变 - 向下/向上/向左/向右/对角方向
  • 径向渐变 -(Radial Gradients)- 由它们的中心定义

线性渐变:

  • 语法:background-image:linear-gradientdirection,color-stop1,color-stop2,……);
    • direction:渐变方向/角度,可选(45deg,to bottom,to top,to right,to left,to left top…)
    • color-stop:选择颜色rgba可以设置透明度,也可以设置色标点区域 例:rgba(255,255,255,0.3) 20%

径向渐变:

  • 语法:background-image: radial-gradient(shape size at position, start-color, …, last-color);
    • shape 参数定义了形状。它可以是值 circle 或 ellipse。其中,circle 表示圆形,ellipse 表示椭圆形。默认值是 ellipse。
    • size:主要用来确定径向渐变的结束形状大小。如果省略了,其默认值为“farthest-corner”
    • at position起点:中心点的位置,可以是关键字(水平方向–left,center,right, 垂直方向–top,center,bottom),具体数值或百分比。

64.响应式布局和自适应布局的区别 ?

  • 响应式布局是指通过CSS媒体查询,根据不同设备或视口宽度设置不同的样式来适应不同屏幕大小,实现页面的自动调整和优化。响应式布局可以使网站在桌面、平板电脑和手机等多种设备上都能够以最佳的显示效果呈现。
  • 自适应布局是指根据屏幕尺寸选择合适的布局方式,使页面在不同设备上看起来更加美观和可读性更好。自适应布局相对来说更加固定一些,它的页面布局通常是由几个固定的布局组成,在不同的屏幕尺寸下选择不同的布局组合来进行展示,而不是像响应式布局那样直接改变样式。

65.z-index失效的几种情况

  • position属性未设置或值为static:如果要使用z-index属性,您需要首先将元素的position属性设置为relative、absolute或fixed。否则,即使设置了z-index,也无法使其生效。
  • 父元素的z-index值高于子元素:当一个父元素和它的子元素都设置了z-index时,子元素的z-index可能会失效。
  • 浮动元素的z-index失效:当使用浮动元素时,z-index属性可能不起作用。这是因为浮动本身就具有一定的层叠性质,并且浮动元素之间的堆叠顺序由它们在文档流中的先后顺序决定。

66.float之后display值改为?

block

67.css中的锚点

<a name="go">来我这里</a>
......
<a href="#go">我来了</a>
  • 1
  • 2
  • 3

可以使用id属性来替代name属性 , 使用id来定义锚点,可以定位针对任何标签来定位。name属性只能针对a标签来定位。

68.移动端1px问题解决方案

  • 利用 css 的 伪元素::after + transfrom 进行缩放
    • 优点:全机型兼容,实现了真正的1px,而且可以圆角。适用于老项目。
    • 缺点:暂用了after 伪元素,可能影响清除浮动。
  • 设置viewport的scale值
    • 优点:全机型兼容,直接写1px不能再方便。
    • 缺点:适用于新的项目,老项目可能改动大。
  • 使用组件库vant/ant-design-mobile

69.阻止移动端H5开发浏览器默认左右滑动行为

html{
    touch-action:none;
}
//此时上下左右都不可滑动
--------改动
html{
touch-action:none;
touch-action:pan-y;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

70.CSS中 定位position 和 transform 移动元素的比较

  • 性能方面:transform性能远高于position
  • 通过translate移动,元素依然会占据其原始空间。如果通过position移动则会改变位置触发重绘

71.margin-left:auto,margin-right:auto,margin:auto区别

margin-left:auto 右对齐

margin-right:auto 左对齐

margin:auto 居中

72.css全屏滚动

overflow-y;overflow-x;scroll-snap-type;scroll-snap-align;必要属性

<style>
        html,
        body {
            height: 100%;
            margin: 0;
        }

        ul {
            margin: 0;
            /* scroll-behavior: smooth 让页面在滚动时拥有平滑的过渡效果,而不是瞬间跳转 */
            scroll-behavior: smooth;
            font-size: 40px;
            width: 100%;
            height: 100%;
            /* 
            overflow-y: auto 表示当内容超出元素的高度时,元素会显示垂直方向的滚动条以便用户浏览。如果内容不超出元素的高度,则不会显示滚动条。
            overflow-x: hidden 则表示当内容超出元素的宽度时,元素不会显示水平方向的滚动条,同时超出部分的内容也将被隐藏。
            */
            overflow-y: auto;
            overflow-x: hidden;
            border: 1px solid #000;
            /* 
            scroll-snap-type: y mandatory; 表示在垂直方向上开启滚动对齐功能,并强制要求元素对齐到滚动容器的边缘。这样可以确保每个子元素都在独立的、整数倍的位置停留,从而实现更加规整的页面布局。
            */
            scroll-snap-type: y mandatory;
            /*设置父级*/
            padding: 0;
        }

        li {
            height: 100%;
            width: 100%;
            flex-shrink: 0;
            /* 
            scroll-snap-align: center; 则表示对齐方式为中心对齐,当子元素的中心点(水平轴和垂直轴的中心点)与滚动容器的中心点重合时,就会触发对齐效果。
            */
            scroll-snap-align: center;
            /*子级设置*/
            text-align: center;
        }

        li:nth-child(1) {
            background-color: teal;
        }

        li:nth-child(2) {
            background-color: gold;
        }

        li:nth-child(3) {
            background-color: green;
        }
    </style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
	<ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
  • 1
  • 2
  • 3
  • 4
  • 5

73.table布局缺点

  • HTML 结构不语义化:使用 table 布局需要使用大量的表格、行和单元格元素,这会导致 HTML 结构不具有语义化。使用 table 布局时,HTML 结构的意义被掩盖,对于阅读和理解 HTML 代码的人来说会带来一定的困难。
  • 代码冗余:为了实现复杂的布局效果,往往需要使用大量的 rowspan 和 colspan 属性,这会导致 HTML 代码变得冗长,难以维护。
  • 不易适应移动端设备:table 布局的实现方式通常需要指定表格的宽度和高度,因此在移动端设备上表现不佳,会导致页面内容被截断或缩小。
  • 渲染性能低下:由于浏览器需要解析大量的表格元素,使用 table 布局会影响页面渲染的性能。
  • 不利于 SEO:由于 table 布局不具备语义化,这会导致搜索引擎难以理解页面的结构和内容,降低网站的 SEO(搜索引擎优化)效果。
  • 不利于响应式布局:由于 table 布局需要指定表格的宽度和高度,因此难以适应不同尺寸的屏幕。对于实现响应式布局,table 布局效果并不是很理想。

三、HTML / CSS 混合篇

1. HTML5、CSS3 里面都新增了那些新特性?

HTML5

  • 新的语义标签
    • article 独立的内容。
    • aside 侧边栏。
    • header 头部。
    • nav 导航。
    • section 文档中的节。
    • footer 页脚。
  • 画布(Canvas) API
  • 地理(Geolocation) API
  • 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
    sessionStorage 的数据在浏览器关闭后自动删除
  • 新的技术webworker, websocket, Geolocation
  • 拖拽释放(Drag and drop) API
  • 音频、视频API(audio,video)
  • 表单控件,calendar、date、time、email、url、searc

CSS3

  • 2d,3d变换
  • Transition, animation
  • 媒体查询
  • 新的单位(rem, vw,vh 等)
  • 圆角(border-radius),阴影(box-shadow),对文字加特效(text-shadow),线性渐变(gradient),旋转(transform)transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);//旋转,缩放,定位,倾斜
  • rgba

四、JS 篇

1. JS 数据类型 ?存储上的差别?

数据类型主要包括两部分:

  • 基本数据+类型: Undefined、Null、Boolean、Number 和 String,Symbol(创建后独一无二且不可变的数据类型 )
  • 引用数据类型: Object (包括 Object 、Array 、Function)

存储区别:

  • 基本数据类型存储在栈中
  • 引用类型的对象存储于堆中

2.数组常用方法?

增:

  • push() 向数组的末尾添加一个或更多元素,并返回新的长度
  • unshift() 在数组开头添加任意多个值,然后返回新的数组长度
  • splice() 传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组
  • concat() 首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组

删:

  • pop() 方法用于删除数组的最后一项,同时减少数组的length 值,返回被删除的项
  • shift() 方法用于删除数组的第一项,同时减少数组的length 值,返回被删除的项
  • splice() 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组
  • slice() 传入两个参数,分别是开始位置和结束位置,不包括结束值,返回一个新数组,不影响原数组

改:

  • splice() 传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响

查:

  • indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
  • includes() 返回要查找的元素在数组中的位置,找到返回true,否则false

3.JavaScript字符串的常用操作方法有哪些?

增:

  • 字符串可以通过‘+’以及${}进行字符串拼接
  • concat 用于将一个或多个字符串拼接成一个新字符串

删:三个函数都接收一个或两个参数,跟数组中slice相似

  • slice()
  • substr() 接受两个参数:起始索引和要提取的字符数
  • substring() 接受两个参数:起始索引和结束索引 不包括结束位置的字符

改:

  • trim()、trimLeft()、trimRight() 删除前、后或前后所有空格符,再返回新的字符串
  • repeat() 接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
  • padStart()、padEnd() 复制字符串,接收两个参数,第一个参数是长度,第二个参数是想要填充的字符,如果小于指定长度,则在相应一边(end/start)填充字符,直至满足长度条件
  • toLowerCase()、 toUpperCase() 大小写转化

查:

  • chatAt() 返回给定索引位置的字符,由传给方法的整数参数指定
  • indexOf() 从字符串开头去搜索传入的字符串,并返回位置(如果没找到,则返回 -1 )
  • startWith() 从字符串中搜索传入的字符串,判断开头字符串是否与期待值相同,并返回一个表示是否包含的布尔值
  • includes() 从字符串中搜索传入的字符串,判断字符串是否包含期待值,并返回一个表示是否包含的布尔值

4.JavaScript字符串的常用转换方法和模板匹配方法?

转换方法:

  • split() 把字符串按照指定的分割符,拆分成数组中的每一项

模板匹配方法:

  • match() 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,返回数组
  • search() 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,找到则返回匹配索引,否则返回 -1
  • replace() 接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素(可用函数)

5.JavaScript 中的类型转换机制

显示转换:

  • Number()
    • 字符串:如果可以被解析为数值,则转换为相应的数值
    • 字符串:如果不可以被解析为数值,返回 NaN
    • 空字符串转换为0
    • 布尔值:true 转成 1,false 转成 0
    • undefined:转成 NaN
    • null:转成0
    • 对象:通常转换成NaN(除了只包含单个数值的数组)
  • parseInt() parseInt相比Number,就没那么严格了,parseInt函数逐个解析字符,遇到不能转换的字符就停下来
  • String() 可以将任意类型的值转化成字符串
    • 特殊:如果接受的是对象则返回[object,object] 如果是数组【1,2,3】返回1,2,3
  • Boolean() 可以将任意类型的值转为布尔值

隐式转换:

  • +运算中,一旦存在字符串,则会进行字符串拼接操作
  • 除了+有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值 。常用就是将字符串转为数值 字符串-0 = 数值

6.null 和 undefined 的区别?

  • null和undefined不能通过==来判断。
  • undefined
    • 这个变量从根本上就没有定义
  • 隐藏式 空值
  • null
    • 这个值虽然定义了,但它并未指向任何内存中的对象
  • 声明式 空值

7. “ ===”、“ ==”的区别?

==: 如果操作数相等,则会返回 true

  • 两个都为简单类型,字符串和布尔值都会转换成数值,再比较
  • 简单类型与引用类型比较,对象转化成其原始类型的值,再比较
  • 两个都为引用类型,则比较它们是否指向同一个对象
  • null 和 undefined 相等
  • 存在 NaN 则返回 false

===:只有在无需类型转换运算数就相等的情况下,才返回 true,需要检查数据类型

区别:

  • 相等操作符(==)会做类型转换,再进行值的比较,全等运算符不会做类型转换

8. “eval是做什么的?

它的功能是把对应的字符串解析成 JS 代码并运行;
应该避免使用 eval,不安全,非常耗性能(2次,一次解析成 js 语句,一次执行)。

9. 箭头函数有哪些特点?

不需要function关键字来创建函数
省略return关键字
改变this指向

10. var、let、const 区别?

var 存在变量提升。
let 只能在块级作用域内访问。
const 用来定义常量,必须初始化,不能修改(对象特殊)

11. new操作符具体干了什么呢?

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。

12.深拷贝浅拷贝的区别?如何实现一个深拷贝?

浅拷贝: 指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝 , 两个对象指向同一个地址

深拷贝: 深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

如何实现深拷贝:

  • JSON.stringify()
  • 手写循环递归
  • _.cloneDeep()
  • MessageChannel 新增
  • jquery的extend

13.对作用域链的理解

  • 作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
  • 简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期

14.JavaScript原型,原型链 ? 有什么特点?

  • 原型:
    • JavaScript的所有对象中都包含了一个 [__proto__] 内部属性,这个属性所对应的就是该对象的原型
    • JavaScript的函数对象,除了原型 [__proto__] 之外,还预置了 prototype 属性
    • 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [__proto__]
  • 原型链:
    • 当一个对象调用的属性/方法自身不存在时,就会去自己 [__proto__] 关联的前辈 prototype 对象上去找
    • 如果没找到,就会去该 prototype 原型 [__proto__] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的“原型链”
  • 原型特点:
    • JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变

15.请解释什么是事件代理

  • 事件代理(Event Delegation),又称之为事件委托。是 JavaScript 中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是可以提高性能
  • 可以大量节省内存占用,减少事件注册,比如在table上代理所有tdclick事件就非常棒
  • 可以实现当新增子对象时无需再次对其绑定

16.Javascript如何实现继承?

  • 构造函数绑定:使用 callapply 方法,将父对象的构造函数绑定在子对象上
  • 实例继承:将子对象的 prototype 指向父对象的一个实例 Cat.prototype = new Animal();
  • 拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象
  • 原型继承:将子对象的 prototype 指向父对象的 prototype F.prototype = Parent.prototype;
  • ES6 语法糖 extends:class ColorPoint extends Point {}

17.谈谈This对象的理解

  • this总是指向函数的直接调用者(而非间接调用者)
  • 如果有new关键字,this指向new出来的那个对象
  • 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window

18.事件模型

W3C中定义事件的发生经历三个阶段:捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling

  • 冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
  • 捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
  • DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件
  • 阻止冒泡:在W3c中,使用stopPropagation()方法;在IE下设置cancelBubble = true
  • 阻止捕获:阻止事件的默认行为,例如click - 后的跳转。在W3c中,使用preventDefault()方法,在IE下设置window.event.returnValue = false

19.new操作符具体干了什么呢?

  • 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
  • 属性和方法被加入到 this 引用的对象中
  • 新创建的对象由 this 所引用,并且最后隐式的返回 this

20.JavaScript中执行上下文和执行栈是什么?

执行上下文: 是一种对Javascript代码执行环境的抽象概念,也就是说只要有Javascript代码运行,那么它就一定是运行在执行上下文中

  • 全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象
  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
  • Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用

执行栈:也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文

  • Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中
  • 每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中
  • 引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

21.typeof 与 instanceof 区别?

typeof 操作符返回一个字符串,表示未经计算的操作数的类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFG2mFwF-1686967105042)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683945877205.png)]

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

区别:

  • typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
  • instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
  • typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断

22.判断是否为数组的5种方法?

  • instanceof data instanceof Array
  • constructor data.constructor == Array
  • Array.isArray() Array.isArray(data) 最推荐
  • typeof typeof(data)
  • Object.prototype.toSrtring.call()

23. 判断一个值是什么类型有哪些方法?

  • typeof 运算符
  • instanceof 运算符
  • Object.prototype.toString.call 方法
  • constructor

24. ajax过程?

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.

25.Ajax原理,ajax优缺点?

  • Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据

  • Ajax的过程只涉及JavaScriptXMLHttpRequestDOMXMLHttpRequestajax的核心机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tk5uFVRn-1686967105043)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683946428125.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R52CumK9-1686967105044)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683946512993.png)]

  • 优点:
    • 通过异步模式,提升了用户体验.
    • 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用.
    • Ajax在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。
    • Ajax可以实现动态不刷新(局部刷新)
  • 缺点:
    • 安全问题 AJAX暴露了与服务器交互的细节。
    • 对搜索引擎的支持比较弱。
    • 不容易调试。

26.bind、call、apply 区别?

bind、call、apply用来改变this指向

apply:接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入

改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次 fn.apply(null,[1,2,3]);

call: 第一个参数也是this的指向,后面传入的是一个参数列表 fn.call(obj,1,2,3)

bind: bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入) 返回的是新的函数

27.如何实现一个bind?

实现bind三步:

  • 修改this指向
  • 动态传递参数
  • 兼容new关键字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Au8o7qGB-1686967105045)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1683947651751.png)]

28.说说你对正则表达式的理解?应用场景?

正则表达式是一种用来匹配字符串的强有力的武器

应用场景:

  • 验证QQ合法性(5~15位、全是数字、不以0开头):
  • 验证手机号格式

29.对事件循环的理解(详细)?

前提: JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环

JavaScript中,所有的任务都可以分为

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环

异步任务分为微任务宏任务:

微任务: 一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前

  • Promise
  • MutaionObserver 监听dom发生改变的
  • Object.observe(已废弃;Proxy 对象替代)
  • process.nextTick(Node.js)

宏任务: 宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

执行顺序:

  • 先执行同步代码,
  • 遇到异步宏任务则将异步宏任务放入宏任务队列中,
  • 遇到异步微任务则将异步微任务放入微任务队列中,
  • 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
  • 微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
  • 一直循环直至所有任务执行完毕。

30.DOM常见的操作有哪些?

  • 创建节点
    • createElement 创建新元素,接受一个参数,即要创建元素的标签名
  • 查询节点
    • querySelector 传入任何有效的css 选择器,即可选中单个 DOM元素(首个) 如果页面上没有指定的元素时,返回 null
    • querySelectorAll 返回一个包含节点子树内所有与之相匹配的Element节点列表,如果没有相匹配的,则返回一个空节点列表
  • 更新节点
    • innerHTML 不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树
    • innerText
    • style dom对象.style.样式属性 = ‘’
  • 添加节点
    • innerHTML
    • appendChild 把一个子节点添加到父节点的最后一个子节点
    • insertBefore(新dom,指定dom对象) 把子节点插入到指定的位置的前面
    • setAttribute 在指定元素中添加一个属性节点,如果元素中已有该属性改变属性值
  • 删除节点
    • removeChild 拿到父节点,要删除的节点dom对象。父.removeChild(子)

31.说说你对BOM的理解,常见的BOM对象你了解哪些?

BOM (Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象 。

浏览器的全部内容可以看成DOM,整个浏览器可以看成BOM

BOM对象:

  • window: Bom的核心对象是window,它表示浏览器的一个实例 。 在浏览器中,window对象有双重角色,即是浏览器窗口的一个接口,又是全局对象
  • location:获取url地址信息
  • navigator: 对象主要用来获取浏览器的属性,区分浏览器类型
  • screen: 保存的纯粹是客户端能力信息,也就是浏览器窗口外面的客户端显示器的信息,比如像素宽度和像素高度
  • history: 主要用来操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定URL跳转

32.BOM和DOM区别?

  • BOM(浏览器对象):与浏览器交互的方法和对象
    • BOM是浏览器对象模型,它指的是将浏览器当作一个对象来对待,这个对象主要定义了与浏览器进行交互的方法和接口
    • BOM的核心是window,而window对象具有双重角色,它既是js访问浏览器窗口的一个接口,又是一个全局对象(Global)
    • 这就意味着网页中定义的任何对象、变量和函数,都会作为全局对象的一个属性或者方法存在
  • DOM(文档对象模型):处理网页内容的方法和接
    • DOM是文档对象模型,它指的是把文档当作一个对象来对待,这个对象主要定义了处理网页的内容和接口

33.如何解决跨域问题?

了解同源策略: 同源是指"协议+域名+端口"三者相同,它是浏览器最核心也最基本的安全功能如果缺少了同源策略,浏览器很容易受到XSSCSRF等攻击

  • 通过jsonp跨域
  • nginx代理跨域
  • nodejs中间件跨域
  • 后端在头部信息中设置安全域名
  • 前端代理

34.异步加载js方式?

  • 设置``属性 async="async" (一旦脚本可用,则会异步执行)
  • 动态创建 script DOMdocument.createElement('script');
  • XmlHttpRequest 脚本注入
  • 异步加载库 LABjs
  • 模块加载器 Sea.js

35.哪些操作会导致内存泄漏?

内存泄漏: JavaScript 内存泄露指对象在不需要使用它时仍然存在,导致占用的内存不能使用或回收

  • 未使用 var 声明的全局变量
  • 闭包函数(Closures)
  • 循环引用(两个对象相互引用)
  • 控制台日志(console.log)
  • 移除存在绑定事件的DOM元素(IE)
  • setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
  • 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收

36.XML和JSON的区别?

  • 数据体积:JSON数据体积更小
  • 数据交互:JSON与JavaScript得交互更加方便,更容易被解析,更好的数据传输
  • 传输速度:JSON传输速度快
  • 数据描述:JSON对数据的描述相比XML较差

37.说说你对递归得理解?

递归: 在数学与计算机科学中,是指在函数的定义中使用函数自身的方法

38.说说你对函数式编程的理解?优缺点?纯函数,高阶函数,柯里化

主要的编程范式有三种:命令式编程,声明式编程和函数式编程

函数式编程: 更加强调程序执行的结果而非执行的过程,简单来讲,就是要把过程逻辑写成函数,定义好输入参数,只关心它的输出结果

纯函数: 纯函数是对给定的输入返还相同输出的函数,并且要求你所有的数据都是不可变的,即纯函数=无状态+数据不可变

  • 函数内部传入指定的值,就会返回确定唯一的值
  • 不会造成超出作用域的变化,例如修改全局变量或引用传递的参数

高阶函数: 是以函数作为输入或者输出的函数被称为高阶函数

柯里化: 把一个多参数函数转化成一个嵌套的一元函数的过程

优点:

  • 更好的管理状态
  • 更简单的复用
  • 减少代码量,提高维护性

缺点:

  • 性能:函数式编程相对于指令式编程,性能绝对是一个短板,因为它往往会对一个方法进行过度包装,从而产生上下文切换的性能开销
  • 资源占用:在 JS 中为了实现对象状态的不可变,往往会创建新的对象,因此,它对垃圾回收所产生的压力远远超过其他编程方式
  • 递归陷阱:在函数式编程中,为了实现迭代,通常会采用递归操作

39.Javascript中如何实现函数缓存?函数缓存有哪些应用场景?

函数缓存,就是将函数运算过的结果进行缓存

实现方式: 实现函数缓存主要依靠闭包、柯里化、高阶函数

应用场景:

  • 对于昂贵的函数调用,执行复杂计算的函数
  • 对于具有有限且高度重复输入范围的函数
  • 对于具有重复输入值的递归函数
  • 对于纯函数,即每次使用特定输入调用时返回相同输出的函数

40. JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
{‘age’:‘12’, ‘name’:‘back’}

41. document.write 和 innerHTML 的区别?

document.write 只能重绘整个页面
innerHTML 可以重绘页面的一部分

42. 请解释一下 JavaScript 的同源策略?

概念:同源策略是客户端脚本(尤其是Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。
这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。
指一段脚本只能读取来自同一来源的窗口和文档的属性。

43. 介绍一下闭包和闭包常用场景?

  • 闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包常见方式,就是在一个函数的内部创建另一个函数
  • 使用闭包主要为了设计私有的方法和变量,闭包的优点是可以避免变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念。
  • 闭包有三个特性:
    • 函数内再嵌套函数
    • 内部函数可以引用外层的参数和变量
    • 参数和变量不会被垃圾回收机制回收
  • 闭包的好处: 能够实现封装和缓存等;
  • 闭包的缺点就是常驻内存,会增大内存使用量,使用不当会造成内存泄漏
  • 应用场景:
    • 常见的防抖节流
    • 使用闭包可以在 JavaScript 中模拟块级作用域
    • 闭包可以用于在对象中创建私有变量

44. javascript的内存(垃圾)回收机制?

  • 垃圾回收器会每隔一段时间找出那些不再使用的内存,然后为其释放内存
  • 标记清除方法(mark and sweep),
    • 这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
    • 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了
  • 引用计数方法(reference counting)
    • 在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。
  • 在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但BOM与DOM对象却是通过引用计数回收垃圾的, 也就是说只要涉及BOM及DOM就会出现循环引用问题。

45. 用js递归的方式写1到100求和?

function add(num1, num2) {
	const num = num1 + num2;
    if(num2 === 100) {
        return num;
	} else {
	    return add(num, num2 + 1)
    }
}
var sum = add(1, 2);              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

46. 事件队列(宏任务微任务)

可以分为微任务(micro task)队列和宏任务(macro task)队列。

微任务一般比宏任务先执行,并且微任务队列只有一个,宏任务队列可能有多个。另外我们常见的点击和键盘等事件也属于宏任务。

下面我们看一下常见宏任务和常见微任务。

常见宏任务:

  • setTimeout()
  • setInterval()
  • setImmediate()

常见微任务:

  • promise.then()、promise.catch()
  • new MutaionObserver()
  • process.nextTick()

微任务和宏任务的本质区别。

  • 宏任务特征:有明确的异步任务需要执行和回调;需要其他异步线程支持。
  • 微任务特征:没有明确的异步任务需要执行,只有回调;不需要其他异步线程支持。
setTimeout(function () {
    console.log("1");
}, 0);
async function async1() {
    console.log("2");
    const data = await async2();
    console.log("3");
    return data;
}
async function async2() {
    return new Promise((resolve) => {
        console.log("4");
        resolve("async2的结果");
    }).then((data) => {
        console.log("5");
        return data;
    });
}
async1().then((data) => {
    console.log("6");
    console.log(data);
});
new Promise(function (resolve) {
    console.log("7");
  resolve()
}).then(function () {
    console.log("8");
});

// 2 4 7 5 8 3 6 async2的结果 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

43.async/await, Generator

async 是一个通过异步执行并隐式返回 Promise 作为结果的函数。是Generator函数的语法糖,并对Generator函数进行了改进。
改进:

  • 内置执行器,无需手动执行 next() 方法。
  • 更好的语义
  • 更广的适用性:co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
  • 返回值是 Promise,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用。
  • async 隐式返回 Promise 作为结果的函数,那么可以简单理解为,await后面的函数执行完毕时,await会产生一个微任务(Promise.then是微任务)。

Generator 是 ES6 引入的新概念,它允许在函数执行过程中暂停和恢复它们的状态。通过 function* 声明一个 Generator 函数,可以在函数体内使用关键字 yield 来生成一个状态,并将函数挂起,等待下一次调用。Generator 函数返回一个可迭代对象,可以通过 next() 方法获取当前生成器的状态值。使用 Generator 函数可以更简单地实现异步操作,避免回调嵌套带来的问题。

48. JavaScript 是单线程的,浏览器是多进程的

  • 每打开一个新网页就会创建一个渲染进程
  • 渲染进程是多线程的
  • 负责页面渲染的 GUI 渲染线程
  • 负责JavaScript的执行的 JavaScript 引擎线程
  • 负责浏览器事件循环的事件触发线程,注意这不归 JavaScript 引擎线程管
  • 负责定时器的定时触发器线程,setTimeout 中低于 4ms 的时间间隔算为4ms
  • 负责XMLHttpRequest的异步 http 请求线程
  • GUI 渲染线程与 JavaScript 引擎线程是互斥的
  • 单线程JavaScript是因为避免 DOM 渲染的冲突,web worker 支持多线程,但是 web worker 不能访问 window 对象,document 对象等。

49.说说 Javascript 数字精度丢失的问题,如何解决?

例子:0.1+0.2===0.3 =>false 涉及IEE754标准

问题原因:

  • 计算机存储双精度浮点数需要先把十进制数转换为二进制的科学记数法的形式,然后计算机以自己的规则{符号位+(指数位+指数偏移量的二进制)+小数部分}存储二进制的科学记数法
  • 因为存储时有位数限制(64位),并且某些十进制的浮点数在转换为二进制数时会出现无限循环,会造成二进制的舍入操作(0舍1入),当再转换为十进制时就造成了计算误差

解决:

  • 使用 toFixed() 方法:将浮点数转化为一个指定位数小数的字符串形式
  • 使用第三方库,Math.jsBigDecimal.js

50.说说你对模块化方案的理解,比如 CommonJS、AMD、CMD、ES Module 分别是什么?

  • CommonJS加载模块同步,主要用于服务器端,它主要依靠require和exports来实现模块化,require用户加载模块,exports用于导出模块
  • AMD异步模块定义,他解决了在浏览器环境下文件以来管理,模块加载的问题。与commonjs不同,AMD使用异步方式加载模块
  • CMD通用模块定义,cmd也是为了解决浏览器端模块化出现的,与AMD不同的是它使用同步方式加载模块,主要依赖require和define来实现模块化
  • ES Module是es6新增的模块化方案,支持在浏览器和node.js使用,并且已经得到了嵌入式运行环境的支持,与commonjs和amd不同,ES Module是静态加载它使用import和export关键字实现模块化

51.用过哪些设计模式?

  • 工厂模式:
    • 工厂模式解决了重复实例化的问题,但还有一个问题,那就是识别问题
    • 主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字
  • 构造函数模式
    • 使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,该模式与工厂模式的不同之处在于,直接将属性和方法赋值给 this对象;

52.javascript有哪些方法定义对象?

  • 对象字面量: var obj = {}; 原型是Object.prototype
  • 构造函数: var obj = new Object();
  • Object.create(): var obj = Object.create(Object.prototype);

53.说说你对promise的了解

54.web开发中会话跟踪的方法有哪些?

  • cookie
  • session
  • url重写
  • 隐藏input
  • ip地址

55.介绍js有哪些内置对象?

  • ObjectJavaScript 中所有对象的父对象
  • 数据封装类对象:ObjectArrayBooleanNumberString
  • 其他对象:FunctionArgumentsMathDateRegExpError

56.eval是做什么的?

  • 它的功能是把对应的字符串解析成JS代码并运行
  • 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)
  • JSON字符串转换为JSON对象的时候可以用eval,var obj =eval('('+ str +')')

57.parseInt函数,[“1”, “2”, “3”].map(parseInt) 答案是多少?

parseInt函数接收两个参数第一个参数是要被解析的字符串,第二个参数是一个可选的进制数。

答案:【1,NaN,NaN】

解析:

  • [‘1’,‘2’,‘3’].map(parseInt)通过map便利的数组会将索引作为第二个参数传入,所以会以parseint(2,1)第二个参数1不是合法的进制数,paeseint(3,2)这里因为3不是二进制数

58.javascript 代码中的"use strict";是什么意思?说说严格模式的限制

  • use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为

限制:

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性
  • 不能使用with语句
  • 禁止this指向window

59.js延迟加载的方式有哪些?

  • 设置``属性 defer="defer" (脚本将在页面完成解析时执行)
  • 动态创建 script DOMdocument.createElement('script');
  • XmlHttpRequest 脚本注入
  • 延迟加载工具 LazyLoad

60.同步和异步的区别?

  • 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作
  • 异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容

61.ES6新特性

  • 增加了letconst命令,用来声明变量。
  • 新增模板字符串(为JavaScript提供了简单的字符串插值功能)
  • 箭头函数
  • for-of(用来遍历数据—例如数组中的值。)
  • arguments对象可被不定参数和默认参数完美代替。
  • 扩展运算符,解构赋值
  • ES6promise对象纳入规范,提供了原生的Promise对象。
  • 增加了块级作用域,let命令实际上就增加了块级作用域。
  • 还有就是引入module模块的概念
  • Generator 生成器
  • 类和继承

62.let,const,var区别?

通过const声明的对象属性不可修改!!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nUkDO8Ka-1686967105046)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1684154487983.png)]

63.let和var区别?

  • let命令不存在变量提升,如果在let前使用,会导致报错
  • 如果块区中存在letconst命令,就会形成封闭作用域
  • 不允许重复声明,因此,不能在函数内部重新声明参数

64.如果new一个箭头函数的会怎么样?

箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数。

65.箭头函数与普通函数的区别?

  • 箭头函数比普通函数更加简洁
  • 箭头函数没有自己的this
  • 箭头函数继承来的this永远不会改变
  • 箭头函数不能走为构造函数
  • 箭头函数没有arguments
  • call,bind,apply无法改变this指向

66.扩展运算符的作用

扩展运算符:(…)

对象扩展运算符:用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中

数组扩展运算符:可以将一个数组转为用逗号分隔的参数序列,且每次只能展开一层数组

67.ES6中模板语法与字符串处理

在es6之前拼接字符串采用的是字符串通过’+'拼接,很麻烦

es6字符模板使用:``结合${变量名}

var name='lc'
var age = 27
var address = 'zg'
var information = `my name ${name},I am ${age} years old this year,I'm from ${address}`
  • 1
  • 2
  • 3
  • 4

68.map与forEach的区别

  • forEach方法,是最基本的方法,就是遍历与循环,默认有3个传参:分别是遍历的数组内容item、数组索引index、和当前遍历数组Array,不会改变原有数组
  • map方法,基本用法与forEach一致,但是不同的,它会返回一个新的数组,所以在callback需要有return值,如果没有,会返回undefined

69.Js动画与CSS动画区别及相应实现

  • CSS3的动画的优点
    • 在性能上会稍微好一些,浏览器会对CSS3的动画做一些优化
    • 代码相对简单
  • 缺点
    • 在动画控制上不够灵活
    • 兼容性不好
  • JavaScript的动画正好弥补了这两个缺点,控制能力很强,可以单帧的控制、变换,同时写得好完全可以兼容IE6,并且功能强大。对于一些复杂控制的动画,使用javascript会比较靠谱。而在实现一些小的交互动效的时候,就多考虑考虑CSS

70.gulp是什么?

  • gulp是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成
  • Gulp的特点:
    • 易于使用:通过代码优于配置的策略,gulp 让简单的任务简单,复杂的任务可管理
    • 构建快速 利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作
    • 易于学习 通过最少的 API,掌握 gulp 毫不费力,构建工作尽在掌握:如同一系列流管道

71.事件的各个阶段, addEventListener

捕获阶段–目标阶段–冒泡阶段

  • 由此,addEventListener的第三个参数设置为true和false的区别已经非常清晰了
    • true表示该元素在事件的“捕获阶段”(由外往内传递时)响应事件
    • false表示该元素在事件的“冒泡阶段”(由内向外传递时)响应事件 默认false

72.数组some函数和every函数

every 函数接受一个函数作为参数,这个函数会被依次应用到数组中的每个元素。该函数应该返回一个布尔值:

  • 如果返回 true,则表示当前元素满足条件,继续检查下一个元素。
  • 如果返回 false,则表示当前元素不满足条件,every 函数将立即返回 false,不再检查后面的元素

some 函数接受一个函数作为参数,这个函数会被依次应用到数组中的每个元素。该函数应该返回一个布尔值:

  • 如果返回 true,则表示当前元素满足条件,some 函数将立即返回 true,不再检查后面的元素。
  • 如果返回 false,则表示当前元素不满足条件,继续检查下一个元素。

73.数组乱序

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    arr.sort(() => Math.random() - 0.5)
  • 1
  • 2

74.如何渲染几万条数据并不卡住界面,requestAnimationFrame

requestAnimationFrame 是一个由浏览器提供的 API,用于优化页面动画、避免出现卡顿、异闻和掉帧的情况。它能够在浏览器下一次重绘之前,通知浏览器调用一个指定的函数来更新动画,从而使得动画呈现更加流畅、自然。

实现流程:假如有一万条数据,我们还需要设置每次渲染条数,总计渲染次数,当前渲染次数三个变量。首先自动执行一次渲染函数(loop),通过条件判断当前渲染次数是否小于总渲染次数进行继续执行,满足条件调用window.requestAnimationFrame(具体渲染函数add);add函数中创建空标签用来接收每次渲染的结构,减少回流次数,当前渲染次数+1,继续执行loop函数

// 插入十万条数据
        const total = 100000
        // 一次插入 20 条,如果觉得性能不好就减少
        const once = 20
        // 渲染数据总共需要几次
        const loopCount = total / once
        // 当前渲染次数
        let countOfRender = 0
        let ul = document.querySelector("ul");
        function add() {
            // 优化性能,插入不会造成回流  createDocumentFragment是一个指向空DocumentFragment对象的引用。下面先将20条插入空元素避免回流
            const fragment = document.createDocumentFragment();
            for (let i = 0; i < once; i++) {
                const li = document.createElement("li");
                li.innerText = Math.floor(Math.random() * total);
                fragment.appendChild(li);
            }
            // 一次性添加dom,减少回流次数
            ul.appendChild(fragment);
            countOfRender += 1;  
            loop();
        }
        function loop() {
            if (countOfRender < loopCount) {
                window.requestAnimationFrame(add);
            }
        }
        loop();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

75.获取到页面中所有的checkbox怎么做

 var domList = document.getElementsByTagName(‘input’)
 var checkBoxList = [];
 var len = domList.length;  //缓存到局部变量
 while (len--) {  //使用while的效率会比for循环更高
   if (domList[len].type == ‘checkbox’) {
       checkBoxList.push(domList[len]);、
   }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

76.怎样添加、移除、移动、复制、创建和查找节点

创建节点:

  • createElement() 创建一个具体元素
  • createDocumentFragment() 创建一个dom片段
  • createTextNode() 创建一个文本节点

添加、移除、替换、插入:

  • appendChild() 添加
  • removeChild() 移除
  • replaceChild() 替换
  • insertBefore() 插入

查找:

  • getElementsByTagName() //通过标签名称
  • getElementsByName() //通过元素的Name属性的值
  • getElementById() //通过元素Id,唯一性

77.window.onload和$(document).ready

  • window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。
  • $(document).ready()DOM结构绘制完毕后就执行,不必等到加载完毕

78.addEventListener()和attachEvent()的区别

  • addEventListener()是符合W3C规范的标准方法; attachEvent()是IE低版本的非标准方法
  • addEventListener()支持事件冒泡和事件捕获; - 而attachEvent()只支持事件冒泡
  • addEventListener()的第一个参数中,事件类型不需要添加on; attachEvent()需要添加'on'
  • 如果为同一个元素绑定多个事件, addEventListener()会按照事件绑定的顺序依次执行, attachEvent()会按照事件绑定的顺序倒序执行

79.数组去重

利用ES6 Set去重(ES6中最常用)

var arr = [1,2,2,2,3,3,3,3];

console.log(new Set(arr))

遍历去重

include,indexof

80.判断两个对象相等

正常通过==比较,不可以判断对象是否相等

需要通过JSON.stringify()先转化为字符串再进行比较

81.防抖节流

节流: 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数,不管在这个中间有多少次触发这个事件,执行函数的频次总是固定的;

防抖: 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间(非常短的时间),当事件密集触发时,函数的触发会被频繁的推迟,只有等待了一段时间也没有事件触发,才会真正的执行响应函数

82.检测浏览器版本版本有哪些方式?

  • 根据 navigator.userAgent UA.toLowerCase().indexOf('chrome')
  • 根据 window 对象的成员 'ActiveXObject' in window

83.javascript基本规范

  • 不要在同一行声明多个变量
  • 请使用===/!==来比较true/false或者数值
  • 使用对象字面量替代new Array这种形式
  • 不要使用全局函数
  • Switch语句必须带有default分支
  • If语句必须使用大括号
  • for-in循环中的变量 应该使用let关键字明确限定作用域,从而避免作用域污

84.npm和yarn,pnpm的优势是什么

npm:

  • npm 是 Node.js 自带的包管理器,因此使用 npm 时不需要另外安装软件包,而且能够使用大量的第三方包。npm 的命令简单易学,而且能够满足大部分项目的需求。

yarn :

  • 提供了更好的性能和速度,安装包时能够并行下载,从而提高了安装的效率
  • 引入了锁定文件的概念,用于确保开发环境和生产环境的包版本一致性,从而避免了由于包版本不兼容而引发的问题。
  • 支持离线模式,如果项目中已经安装了所需的包,yarn 不需要从互联网中下载包,而是直接使用本地缓存中的包。

pnpm:

  • 最大优势是节约磁盘空间 pnpm 只在项目中安装一份软件包
  • pnpm 不需要重新安装所有依赖项,而是对每个工程和依赖进行增量安装

85.导致页面加载白屏时间长的原因有哪些,怎么进行优化

原因:

  • 大量 HTTP 请求:在页面加载过程中,浏览器需要请求服务器获取页面的 HTML、CSS、JavaScript、图片等资源,如果请求过多,会导致页面加载时间变长。可以通过减少 HTTP 请求的数量来优化加载速度,例如合并 CSS 和 JavaScript 文件,压缩图片等。
  • 大量 JavaScript 代码:当浏览器下载并解析 JavaScript 代码时,页面的渲染会被阻塞,这也会导致页面加载时间变长。可以通过将 JavaScript 代码异步加载、延迟加载或分割成多个小文件来优化加载速度。
  • 大量 CSS 代码:与 JavaScript 类似,CSS 代码也会阻塞页面渲染,可以通过压缩 CSS 代码、减少 CSS 文件的大小和数量、使用外部链接等方法来优化加载速度。
  • 服务器响应时间过长:如果服务器响应时间过长,也会导致页面加载时间变长。可以通过升级服务器硬件、优化代码等方式来减少服务器响应时间。
  • 不合理的 DOM 结构:如果页面的 DOM 结构不合理,也会导致页面加载时间变长。可以通过减少 DOM 节点数量、避免使用 table 布局、使用 CSS Sprite(雪碧图) 等方式来优化加载速度。

优化:

  • 压缩 HTML、CSS、JavaScript、图片等资源,减少文件大小。
  • 合并 CSS 和 JavaScript 文件,减少 HTTP 请求的数量。
  • 将 JavaScript 代码异步加载、延迟加载或分割成多个小文件。
  • 使用浏览器缓存,避免重复下载资源。
  • 使用外部链接或 CDN 加速器等方式来加速资源加载。
  • 减少 DOM 节点数量,避免使用 table 布局等方式来优化页面渲染速度。

86.DOM克隆操作

深克隆(克隆元素内文本节点加上所有后辈元素节点),

浅克隆(克隆元素本身,不克隆文本节点和后辈节点)

cloneNode()接受一个可选值为true或false的参数。True 表示克隆元素和它的所有子节点。False表示克隆元素但不包含它的子节点

87.沙箱模式

沙箱模式是一种软件设计模式,用于创建一个独立的、受保护的执行环境,隔离代码与外部世界的交互,并限制代码所能访问的资源和功能。在JavaScript中,沙箱模式通常通过将代码封装在匿名函数中并立即调用来实现。这样可以创建一个私有作用域,其中的变量也不会泄漏到全局作用域,从而避免了变量名冲突和数据污染。

虽然闭包和沙箱模式是不同的概念,但它们可以相互结合,以实现更高级别的编程需求。例如,可以使用闭包来创建一个沙箱,限制函数所能访问的变量范围。这种组合可以使代码更加清晰、安全和易于维护。

88.string和tostring什么区别

string和ToString方法的区别在于它们的作用不同。

string是一种数据类型,用于存储和处理字符串,而ToString是一个通用方法,用于将数据转换为字符串。当我们需要将一些非字符串类型的数据转换为字符串时,就可以使用ToString方法来实现。

toString接收一个参数。可将数值字符串转化为对应进制数

string可以将任何数据类型转化为字符串,toString不可以转换null和undefined

89.js数据存储方式

  • Cookie:Cookie是一种在浏览器端存储数据的机制,它可以支持长期存储数据,并且数据可以在不同的页面之间共享。使用JavaScript可以通过document.cookie属性来操作Cookie。
  • Web Storage:Web Storage提供了Session Storage和Local Storage两种机制,都是HTML5新增的。Session Storage用于临时性的会话数据存储,数据在用户关闭浏览器后将被清除,而Local Storage则可以长期存储数据,即使用户关闭浏览器也不会丢失。使用JavaScript可以通过window.sessionStorage和window.localStorage对象来操作这两种存储机制。
  • IndexedDB:IndexedDB是一种在浏览器中存储大量结构化数据的机制,它类似于一个本地数据库。IndexedDB提供了一个异步的API,可以在浏览器中建立对象存储空间,在其中存储键值对数据。使用JavaScript可以通过IndexedDB API来操作这种存储机制。
  • Web SQL:废弃

90.cookie,session,token区别

  • Cookie:Cookie是在用户端存储数据的一种机制,它可以存储一些简单的用户信息和标识。服务器通过设置Cookie并发送到客户端,在下次请求时客户端会自动携带该Cookie,从而实现对用户身份的验证或其他操作。Cookie的缺点是可能面临安全问题,因为Cookie存储在客户端,容易遭受窃取或伪造攻击。
  • Session:Session是在服务器端存储数据的一种机制,它可以保存一些复杂的用户信息和状态,用于实现对用户身份的验证和跟踪。服务器使用一个唯一的Session ID来和客户端进行交互,从而避免了安全性问题。但是Session也存在一些缺点,例如对服务器负载压力较大等问题。
  • Token:Token是一种包含用户身份和权限信息的加密字符串,通常由服务器生成并发送给客户端。客户端使用Token代替Cookie或Session来进行身份验证和数据传输。Token的优点是可以减轻服务器压力,减少网络流量和延迟,并且减少了安全性问题。Token的缺点是需要保证其加密和传输的安全性。

Cookie适用于简单的身份验证和数据存储,Session适用于需要复杂状态管理和用户跟踪的场景,而Token则更适合于分布式系统和APP等跨平台的数据传输。

91.js十进制转二进制

  • 使用 toString() 方法和参数 2:
let num = 123
num.toString()  //'123'
num.toString(2)  //'1111011'
  • 1
  • 2
  • 3

92.如何让多个异步函数顺序执行

  • 使用 Promisethen 方法链接异步任务。

  • 使用 async/await 关键字。

93.settimeout事件机制

setTimeout() 方法的实现基于事件机制,它会将回调函数添加到事件队列中。当指定的延迟时间到达后,该回调函数被推入到事件队列的最后,等待 JavaScript 引擎空闲时执行。

由于 JavaScript 的单线程特性和事件循环机制,多个任务可能会阻塞事件队列,从而导致异步代码无法按照预期的顺序执行,我们需要合理地使用定时器以避免这种情况。

如果设置的延迟时间小于 4 毫秒,则实际的延迟时间可能会大于设置值,因为浏览器通常会使用 4 毫秒的最小时间间隔来执行定时器任务。

94.bind连续绑多次最终this指向

先看代码:

function say() {
	alert(this.x);
};
var a = say.bind({x: 1});
var b = a.bind({x: 2});
b(); // 这里会输出1还是2呢?    答案:1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

无论使用bind绑定多少次,最终原函数的this值是由第一次绑定传的参数决定的。

95.mep和set

  • Map:可迭代的集合,其中每个元素都由一个键和一个相应的值组成。Map 中的键可以是任何类型,而值也可以是任何类型,包括对象引用和原始值。
  • Set:一种只含有唯一值的集合,不允许出现重复项。Set 中的值可以是任何类型,包括对象引用和原始值。

96.大文件上传

  1. 分片上传:将大文件分成多个小文件,每个小文件单独上传,最后在服务器端进行合并操作,这样可以减少上传和下载的时间,并且一旦上传失败只需要重新上传失败的那个分片,而不需要整个文件重新上传。
  2. 断点续传:在分片上传的基础上,可以利用本地存储技术记录已经上传的分片信息,当上传失败时,可以根据已经上传的分片信息来继续上传失败的那个分片,从而实现断点续传。
  3. 流式上传:在传统的上传方式中,文件需要完全读入内存才能上传,而在流式上传中,文件是按照流的方式逐个读取上传,可以避免一次性读取整个大文件,从而减少内存的占用。
  4. 压缩上传:对于某些文件类型,比如文本文件、图片、视频等,可以先对其进行压缩再上传,可以减少文件的大小并加快上传速度。
  5. 使用断电续传 SDK:除了自己实现断点续传外,也可以使用一些第三方的断点续传 SDK,如七牛、阿里云等都提供了相关的 SDK,可以简化大文件上传的实现。

97.移动端Click300毫秒点击延迟 解决办法

产生原因: 浏览器需要等待一段时间(大约 300 毫秒)来检测用户是单击还是双击。

  • 使用 FastClick:FastClick 是一个 JavaScript 插件,它可以通过消除移动浏览器上的点击延迟来提高 Web 应用程序的响应速度。使用 FastClick 只需要在页面加载完成后引入库文件,并在需要绑定快速点击的元素上通过 FastClick.attach(element) 方法进行绑定即可。
  • 使用 touch 事件:如果不想使用第三方库或插件,也可以通过原生的 touch 事件来模拟快速点击。例如,可以通过监听 touchstart 事件来代替 click 事件,实现更快的响应速度。
  • 设置 meta 标签:将以下 meta 标签添加到 HTML 文件的 head 标签中,可以告诉浏览器不要缩放页面,并且禁用缩放手势,从而提高点击响应速度:

98.如何判断一个对象为空对象

通过 Object.keys(obj) 方法获取对象的所有属性名,并判断属性数量是否为 0 来实现 、

let obj = {'name':'zs'}
Object.keys(obj).length     //1
let objs = {}
Object.keys(objs).length	//0
  • 1
  • 2
  • 3
  • 4

99.数组常用方法

  • push:向数组末尾添加一个或多个元素,并返回新的长度。
  • pop:删除并返回数组最后一个元素。
  • shift:删除并返回数组第一个元素。
  • unshift:向数组开头添加一个或多个元素,并返回新的长度。
  • concat:合并两个或多个数组,并返回新的数组。不改变原数组。
  • join:将数组中的所有元素转化为字符串,并用指定的分隔符连接起来。
  • slice:返回数组的一个片段(浅拷贝),不影响原数组。
  • splice:在数组中添加或删除元素,可修改原数组。
  • sort:对数组元素进行排序,默认按照 Unicode 码点升序排列,可传入回调函数实现自定义排序。
  • reverse:翻转数组元素顺序,改变原数组。
  • indexOf:查询元素在数组中第一次出现的位置,找到返回其下标,否则返回-1。
  • lastIndexOf:从数组末尾开始查询元素在数组中最后一次出现的位置,找到返回其下标,否则返回-1。
  • filter:返回由满足回调函数条件的所有元素组成的新数组,不改变原数组。
  • map:返回一个新数组,其中的元素是对原有数组元素应用回调函数后得到的结果。
  • reduce:累加器方法,对数组的每个元素(从左到右)执行一个回调函数,返回单个值。
  • some:判断数组是否具有满足条件的值,有就返回true
  • every:判断数组所有值是否都满足条件,都满足返回true
  • forEach:循环数组

100.数组扁平化

  • 使用递归
  • 使用 reduce 方法:reduce 方法可以用来将数组中的每个元素累加到一个结果中
  • 使用 flat 方法:
    • ES2019 中引入了数组的 flat 方法,可以将嵌套的数组扁平化成一维数组。
    • flat 方法只能够将嵌套的层数降至一维,如果需要将多维数组扁平化成一维数组,则需要传递一个大于等于嵌套层数的参数 arr.flat( Infinity ), Infinity 表示扁平化任何深度的嵌套数组

101.for…in 和 for … of区别

for…in 循环是用来遍历对象属性的,它可以枚举目标对象的所有可枚举属性,包括继承链上的属性,但遍历的顺序是不确定的

for…of 循环是用来遍历可迭代对象 (Iterable) 的,它可以遍历数组、字符串、Map、Set 等内置的可迭代对象,但不能遍历普通的对象,也不能遍历对象的属性

区别:

  • for…in遍历数组返回下标,遍历对象返回键
  • for…of遍历数组返回数据,不可以遍历普通对象

102.伪数组,伪数组转换为数组

伪数组是一种类数组对象,它具有类似数组的结构和特性,但并不是真正的数组。

在 JavaScript 中,常见的伪数组包括函数参数 arguments、DOM 元素集合 NodeListHTMLCollection 等。

伪数组和数组区别:

  • 伪数组没有数组的方法和属性(如 push、pop、length),不能使用数组相关的循环方法(如 forEach、map、reduce)等。但它们具有类数组的结构,可以通过下标来访问元素,并且拥有 length 属性

转换: Array.from() 方法或者扩展运算符

103.二维数组应用场景

  • 游戏开发: 在游戏开发中,二维数组通常被用来表示游戏场景、地图、迷宫等
  • 图像处理: 在图像处理中,二维数组常用于表示图像的像素点,每个像素点可以用一个颜色值来表示
  • 数字计算: 在数学计算中,二维数组经常用于存储和处理矩阵

五、Vue 篇

1. 谈谈你对MVVM开发模式的理解?

MVVM是一种简化用户界面的实践驱动编程方式。在当前主流的前后端分离的开发模式中,MVVM模式的优越性日益体现,相较于经典的MVC模式,其对于程序模块的封装很好地解决了前后端信息交互的冗余和繁琐

MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。

为什么使用MVVM:低耦合,可复用,独立开发,可测试

2. v-if 和 v-show 有什么区别?

  • 手段
    • v-if是动态的向DOM树内添加或者删除DOM元素;
    • v-show是通过设置DOM元素的display样式属性控制显隐;
  • 编译
    • v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;
    • v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;
  • 性能消耗:
    • v-if有更高的切换消耗;
    • v-show有更高的初始渲染消耗
  • v-if指令可以应用于template包装元素上,v-show不支持

3. r o u t e 和 route和 routerouter区别

  • $route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数
  • $router 是“路由实例”想要导航到不同URL 对象包括了路由的跳转方法,钩子函数等。通过push、replace、go、back等方法,来实现页面间的跳转

4.vue自定义指令

vue指令

vue2

局部注册:directive选项

directives: {
    'focus': {
      bind(el, binding, vnode) {
        el.focus()
      }
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

全局注册:main.js

Vue.directives('focus',{
	bind(el, binding, vnode) {
        el.focus()
      }
})
  • 1
  • 2
  • 3
  • 4
  • 5

生命周期

  • bind:只调用一次,指令第一次绑到元素调用,用于初始化
  • inserted:被绑定元素插入父节点时调用
  • update:所在组件vnode更新调用
  • componentUpdate:指令在组件的vnode及子组件的vnode全部更新完调用
  • ubind:只调用一侧,指令解绑

vue3

局部注册:引入 import { Directive , DirectiveBinding } from ‘vue’ 分别校验vFocus,binding

<template>
  <input type="text" v-focus="{ color: 'red' }" />
</template>

<script setup>
const vFocus = {
  created(el, binding) {
    el.style.backgroundColor = binding.value.color;
    console.log(el, binding.value.color); //<input type="text" style="background-color: red;"> 'red'
  },
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

全局注册:main.js,app.vue如上引入

import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)

app.directive('focus', {
    created(el, binding) {
        el.style.backgroundColor = binding.value.color;
        console.log(el, binding.value.color); //<input type="text" style="background-color: red;"> 'red'
    }
})

app.mount('#app')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

生命周期

  • created 元素初始化的时候
  • beforeMount 指令绑定到元素后调用 只调用一次
  • mounted 元素插入父级dom调用
  • beforeUpdate 元素被更新之前调用
  • update 这个周期方法被移除 改用updated
  • beforeUnmount 在元素被移除前调用
  • unmounted 指令被移除后调用 只调用一次

5.vue项目优化

  • 代码层面
    • 长列表性能优化: Object.freeze 方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了
    • 事件销毁, beforeDestroy生命周期函数内执行销毁逻辑。
    • 图片懒加载
    • 路由懒加载
    • 按需加载插件
    • v-if,v-for避免同时使用,v-for遍历添加key
    • v-if,v-show选择
    • keep-alive组件缓存
    • input防抖节流
  • 基础的web技术优化
    • 开启gzip压缩
    • 浏览器缓存
    • CDN加速
  • webpack优化

6.vue模板如何编译

Vue的模板编译就是将“HTML”模板编译成render函数的过程。这个过程大致可以分成三个阶段:

  • 解析阶段:将“HTML”模板解析成AST语法树;
    • 核心 parseHTML( template ,{}) Vue定义了很多匹配HTML的正则表达式 ,parseHTML根据正则匹配
    • parseHTML是解析模板字符串的“主线程”,它的第一个参数是要解析的模板字符串, 也就是单文件组件中最外层 所包裹的部分;第二个参数是一个选项对象,它会包含一些回调,以及一些配置项。
    • 选项对象:
      • start( tag, attrs, unary ) 匹配到开始标签时的回调,tag为当前标签的标签名,attrs为该标签上的属性列表,unary为当前标签是否为自闭合标签
      • end() 匹配到结束标签时的回调
      • chars(text) 匹配到文本节点的回调
      • comment(text) 匹配到注释节点的回调,其处理逻辑跟文本的处理逻辑类似
  • 优化阶段:从AST语法树中找出静态子树并进行标记(被标记的静态子树在虚拟dom比对时会被忽略,从而提高虚拟dom比对的性能);
    • 上面简单介绍过,优化阶段的工作就是标记静态子树,标记静态子树后主要有以下两个优点:
      • 生成虚拟dom的过程中,如果发现一个节点是静态子树,除了首次渲染外不会生成新的子节点树,而是拷贝已存在的静态子树;
      • 比对虚拟dom的过程中,如果发现当前节点是静态子树,则直接跳过,不需要进行比对。
    • 标记静态子树的过程分为两个步骤:
      • 遍历AST语法树,找出所有的静态节点并打上标记(注:当前节点及其所有子节点都是静态节点,当前节点才会被打上静态节点的标记)
      • 遍历经过上面步骤后的树,找出静态根节点,并打上标记(注:静态根节点是指本身及所有子节点都是静态节点,但是父节点为动态节点的节点,找到了静态根节点也就找到了“静态子树”)
  • 代码生成阶段:通过AST生成代码字符串,并最终生成render函数。

7.vue2响应式原理

vue 采用了几个核心部件 : ObserverDep WatcherScheduler

  • observer把一个普通的对象转换成响应式的对象
    • observer 把对象的每个属性通过 object.defineProperty 转换为带有 getter 和 setter 的属性
  • Dep 表示依赖, vue 会为响应式对象中的每一个属性,对象本身,数组本身创建一个 dep 实例,每个 dep 实例都可以做两件事情 :
    • 记录依赖:是谁在用我
    • 派发更新:我变了,我要通知那些用我的人
  • watcher 在函数执行的过程中,如果发生了依赖记录,那么 dep 就会把这个全局变量记录下来,表示有一个 wathcer 用到了我这个属性。
  • Scheduler 不会立即执行更新,通过nexttick异步更新

8.vue3响应式原理

通过Proxy(代理): 拦截对象中任意属性的变化,包括:属性值的读写,属性的增加,属性的删除等。

通过Reffect(反射): 对源对象的属性进行操作, Reflect不是一个函数对象,因此它是不可构造的。

9.刷新浏览器后,Vuex的数据是否存在?如何解决?

不存在

原因: 因为 store 里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化。

我们有两种方法解决该问题:

  1. 使用 vuex-along
  2. 使用 localStorage 或者 sessionStroage

10.vue和react共同点?区别

共同点:

  • 数据驱动视图
  • 组件化
  • 都使用 Virtual DOM

不同点

  • 核心思想不同
    • vue定位就是尽可能的降低前端开发的门槛,让更多的人能够更快地上手开发。这就有了vue的主要特点:灵活易用的渐进式框架,进行数据拦截/代理,它对侦测数据的变化更敏感、更精确
    • react 定位就是提出 UI 开发的新思路 React推崇函数式编程(纯组件),数据不可变以及单向数据流,当然需要双向的地方也可以手动实现, 比如借助onChangesetState来实现。
  • 组件写法
    • React推荐的做法是JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中
    • Vue 推荐的做法是 template 的单文件组件格式(简单易懂,从传统前端转过来易于理解),即 html,css,JS 写在同一个文件(vue也支持JSX写法)
  • diff算法
  • 响应式原理
    • vue2采用object.defineProperty ,vue3采用proxy,reflect
    • React基于状态机,手动优化,数据不可变,需要setState驱动新的state替换老的state。

11.vue双向数据绑定原理

简易实现:v-model分为两部分,通过v-bind绑定值,再通过v-on:input来通步修改值

原理

  • 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
  • 通过dep来理清依赖关系,watcher在依赖中添加自身
  • compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  • 待属性变动dep.notice()通知时,能调动watcher自身的update方法,并处罚compile回调渲染视图

12.computed和watch区别

computed计算属性,watch监听属性

  • 计算属性不在 data 中,它是基于data 或 props 中的数据通过计算得到的一个新值。watch 可以监听的数据来源:data,props,computed内的数据
  • component中有get和set方法,会默认缓存计算结果。watch不支持缓存,支持异步, immediate监听属性立即执行一次,deep开启深度监听

13.Vuex

Vuex是一种状态管理模式,存在的目的是共享可复用的组件状态。

主要包括以下几个模块:

  • State => 基本数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态。
  • Getter => 从基本数据派生的数据,允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
  • Mutation => 是唯一更改 store 中状态的方法,且必须是同步函数。
  • Action => 像一个装饰器,包裹mutations,使之可以异步。用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
  • Module => 模块化Vuex,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

14.vuex辅助函数

mapState, mapMutations, mapActions, mapGetters

mapState和mapGetters:

  • 两者都放在 computed中,以mapState举例
import { mapState } from 'vuex'

computed中
computed:{
	...mapState(['data'])  //data是vuex存放的state中的属性,此时{{data}}可使用
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

mapMutations, mapActions:

  • 放在组件的methods属性中 。使用与上类似

15.vuex模块化使用

当我们开发的项目比较大时,store中的数据就可能比较多,这时我们store中的数据就可能变得臃肿,为了解决这一问题,我们就需要将store模块化(module)

前提:创建两份js文件,含有属性与vuex写法相同,需要通过 namespaced:true开启命名空间store/index.js:在modules中引入文件

使用:

  • 访问state数据:
    • 第一种方式:this.$store.state.moduleA.sum
    • 第二种方式: ...mapState('moduleA',['sum','number'])
  • action提交mutation
  • 第一种方式:需要传参this.$store.dispatch('moduleB/addZhang',{name:'小明',age:18}) ,无需传参this.$store.dispatch('moduleB/addServer')
  • 第二种方式:...mapActions('moduleB',['addZhang'])
  • getters计算属性
  • 第一种方式: this.$store.getters['moduleB/firstName']
  • 第二种方式:...mapGetters('moduleB',['firstName'])

16.vue中mixin

mixin(混入): 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如datacomponentsmethods createdcomputed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

具体使用:

  • 创建mixins.js文件
let mixin = {
    created() {
        console.log('我是mixin中的');
    },
    methods: {
        hellow() {
            console.log('你好');
        },
    },
}
export default mixin
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 局部使用
import mixin from "./mixins";
export default {
  mixins: [mixin],
  mounted() {
    this.hellow();//你好
  },
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 全局使用main.js
import { createApp } from 'vue'
import App from './App.vue'
import mixins from "./mixins";
const app = createApp(App)
app.mixin(mixins)
app.mount('#app')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

17.Vue中给对象添加新属性时,界面不刷新怎么办?

原因:vue2响应式采用object.defineProperty进行劫持,那个添加新属性时,新的属性不会具有get和set方法,不是一个响应式所以界面不刷新

解决:Vue.set() 向响应式对象中添加一个property,并确保这个新 property 同样是响应式的

vue3通过proxy劫持和reflect映射实现响应式,不会有这个问题

18.vue组件通讯方式

  • 通过 props 传递
    • props校验:name:{type:String,required:true,default:默认值} required是否必要
  • 通过 $emit 触发自定义事件
  • 使用 ref
  • EventBus
  • Provide 与 Inject
  • Vuex

19.vue3setup的父传子怎么去写?

介绍三种方法:

第一种:使用vue2写法通过props和$emit

第二种:setup函数写法

  • setup(props,context),通过props接收数据,通过context.emit(‘调用父组件方法’,传递参数)

第三种:script中setup

  • vue3自带defineProps,defineEmits
const emits = defineEmits(["changeNumber"]);
// 也可以不赋值,取值通过{{num}}获取
const props = defineProps({
  num: {
    type: Number,
    default: () => [],
  },
  list: {
    type: Array,
  },
});
const changeNum = function () {
  emits("changeNumber", 888);
  //   console.log(11111111111);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

20.setup可不可以直接写async和await?

可以

setup 语法糖中可直接使用 await,不需要写 async , setup 会自动变成 async setup

<script setup>
  import Api from '../api/Api'
  const data = await Api.getData()
  console.log(data)
</script>
  • 1
  • 2
  • 3
  • 4
  • 5

21.vue生命周期

vue2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8P7sspQX-1686967105047)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685089235304.png)]

beforeCreate – 首次访问data

created – 首次访问this生命周期

mounted – 页面展示

vue3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfSFfojq-1686967105048)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685089301710.png)]

区别

  • beforeCreate -> setup() 开始创建组件之前,创建的是data和method
  • created -> setup()
  • beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
  • mounted -> onMounted 组件挂载完成后执行的函数
  • beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
  • updated -> onUpdated 组件更新完成之后执行的函数。
  • beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
  • destroyed -> onUnmounted 组件卸载之前执行的函数。dszhuoyi
  • activated -> onActivated 组件卸载完成后执行的函数
  • deactivated -> onDeactivated

22.说说 Vue 中 CSS scoped 的原理

添加scoped标签后会给组件中所有标签元素,添加一个唯一标识,这个唯一标识就是自定义属性,data-v-xxxxxxxx这样的字眼,同时对应的样式选择器也会添加这个唯一的属性选择器

23.$nextTick原理

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

nextTick原理

24.data是函数不是对象

vue是一个单页面应用最终所有的实例都会挂载到app.vue文件,如果data是一个对象那么会导致数据污染。通过函数返回对象的方式,利用函数作用域的限制避免数据污染

25.路由守卫

vue路由守卫分为三种:全局路由守卫,独享路由守卫,组件路由守卫

to: 进入到哪个路由去

from: 来自哪个路由

next:是否跳转

  • 全局守卫: router.beforeEach((to,from,next)=>{})
  • 独享路由守卫: beforeEnter:(to,from,next)=>{}
  • 组件路由守卫: beforeRouteEnter:(to,from,next)=>{}, beforeRouteUpdate , beforeRouteLeave

26.vue设置全局变量

方法一:

  • vue2.x挂载全局是使用 Vue.prototype.$xxxx=xxx 的形式来挂载,然后通过 this.$xxx来获取挂载到全局的变量或者方法。
  • Vue 3 中,使用 config.globalProperties 、app.config.globalProperties.$data = ‘111’
 const {proxy} = getCurrentInstance()
 console.log(proxy.$data)
  • 1
  • 2

方法二:

  • provide/inject

27.vue中keep-alive

属性:includeexclude

语法:

// 指定home组件和about组件被缓存
<keep-alive include="home,about" >
    <router-view></router-view>
</keep-alive>

// 除了home组件和about组件别的都缓存
<keep-alive exclude="home,about" >
    <router-view></router-view>
</keep-alive>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

钩子函数:

  • activated 当组件被激活(使用)的时候触发 可以简单理解为进入这个页面的时候触发
  • deactivated 当组件不被使用(inactive状态)的时候触发 可以简单理解为离开这个页面的时候触发

进入开启缓存的组件

初始进入和离开 created ---> mounted ---> activated --> deactivated
后续进入和离开 activated --> deactivated
  • 1
  • 2

28.vue插槽

slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽。

默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。

具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。

作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm. s l o t 中,默认插槽为 v m . slot中,默认插槽为vm. slot中,默认插槽为vm.slot.default,具名插槽为vm. s l o t . x x x , x x x 为插槽名,当组件执行渲染函数时候,遇到 s l o t 标签,使用 slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用 slot.xxxxxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

29.vue2和vue3区别

双向绑定更新

vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.defineProperty()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。

vue3 中使⽤了 ES6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。

这⾥是相⽐于vue2版本,使⽤proxy的优势如下

1.defineProperty只能监听某个属性,不能对全对象监听 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)

2.可以监听数组,不⽤再去单独的对数组做特异性操作,通过Proxy可以直接拦截所有对象类型数据的操作,完美⽀持对数组的监听。

获取props

vue2在script代码块可以直接获取props,vue3通过setup指令传递

API不同

Vue2使⽤的是选项类型API(Options API),Vue3使⽤的是合成型API(Composition API)

建立数据data

vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。

生命周期不同

vue2 -------- vue3

beforeCreate -> setup() 开始创建组件之前,创建的是data和method

created -> setup()

beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。

mounted -> onMounted 组件挂载完成后执行的函数

beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。

updated -> onUpdated 组件更新完成之后执行的函数。

beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。

destroyed -> onUnmounted 组件卸载之前执行的函数。dszhuoyi

activated -> onActivated 组件卸载完成后执行的函数

deactivated -> onDeactivated

是否支持碎片:vue2.0 只允许有一个根标签,vue3.0支持碎片化,可以拥有多个根节点

main.js文件不同:vue2中我们可以使用pototype(原型)的形式去进行操作,引入的是构造函数 vue3中需要使用结构的形式进行操作,引入的是工厂函数

diff算法不同

更好的支持ts

30.Vue3.0 所采用的 Composition Api (组合式)与 Vue2.x 使用的 Options Api(选项式) 有什么不同?

  • options Api 当组件变得复杂,导致对应属性的列表也会增长,这可能会导致组件难以阅读和理解 。composition Api它将功能定义在一起,利于查找和理解
  • Composition API tree-shaking 友好,代码也更容易压缩
  • Composition API中见不到this的使用,减少了this指向不明的情况
  • 如果是小型组件,可以继续使用Options API,也是十分友好的

31.vue3中hook

本质是一个函数,把setup函数中使用的Composition API(组合式api)进行了封装,类似于vue2中的mixin

自定义hook优势:复用代码,让setup中的逻辑更清楚易懂

32.vue组件和插件的区别

组件: Vue 组件是一个可复用的 Vue 实例,可以带有自己的状态和方法。组件可以包含其他组件,从而形成一个复杂的 UI 列表。

优点

  • 可以将代码封装成一个可复用的组件,提高开发效率。
  • 组件具有良好的可维护性,易于修改和更新。

缺点

  • 组件的功能和作用比较独立,不太适用于全局功能的扩展。
  • 组件的管理和组织需要一定的规范,否则可能会导致混乱和不易维护。

插件: Vue 插件可以扩展 Vue 的全局功能,在应用程序中可以重复使用。常见的插件如 vue-routervuexaxios 等。

优点

  • 插件可以方便地扩展 Vue 的全局功能。
  • 插件可以使代码重复利用,提高开发效率。
  • 开源社区中已经有大量的插件可以用于解决常见的问题。

缺点

  • 插件具有一定的复杂性,需要更多的学习成本。
  • 插件功能可能比较复杂,可能会导致性能下降。

33.vue修饰符

Vue中,修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理

  • 表单修饰符
    • .lazy 懒加载,光标离开标签时,才赋值给value
    • .trim 过滤首位空格
    • .number 限制输入类型为数字或转为数字
  • 事件修饰符
    • .stop 阻止事件冒泡
    • .prevent 组织事件默认行为
    • .once 事件只触发一次
    • .capture 开启事件捕获
    • .self 事件只在自身触发
  • 鼠标按键修饰符
    • left 左键点击
    • right 右键点击
    • middle 中键点击
  • 键值修饰符
    • 普通键(enter、tab、delete、space、esc、up…)
    • 系统修饰键(ctrl、alt、meta、shift…)
  • v-bind修饰符
    • .async 对props进行双向绑定
    • .prop 设置自定义标签属性,避免暴露数据,防止污染html结构
    • .camel 将命名为驼峰命名法

34.Vue路由中,history和hash两种模式有什么区别?

hash: hash 模式是一种把前端路由的路径用井号 # 拼接在真实 URL 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 hashchange 事件。

  • 优点:浏览器兼容性较好,连 IE8 都支持
  • 缺点:路径在井号 # 的后面,比较丑

history: history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求

  • 优点:路径比较正规,没有井号 #
  • 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了

35.params和query区别

paramsquery 都是用于传递参数的,但它们的传参方式和使用场景是不同的。

params 通过路由路径传递参数,在路由配置中使用 :paramName 的形式进行声明

const router = new VueRouter({
  routes: [
    {
      path: '/user/:id',
      component: User,
    },
  ],
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

query 通过 URL 查询字符串(即问号后面的部分)传递参数,在路由地址后面使用 ? 连接多个参数键值对

不需要在router中配置 /search?q=vue 会自动匹配到search组件

区别:

  • params 适合用于必须存在的参数传递,例如用户详情页或文章详情页的访问。
  • query 适合用于可选的参数传递,例如搜索功能中关键词的传递。

36.vue2中assets和vue3中public区别 ?

在 Vue 2 中,assets 目录是默认存在的,可以直接在项目的根目录下创建,它通常用来存放组件需要的图片、样式等静态资源文件。这些文件会被打包到 JavaScript 文件中,在代码中使用相对路径引用。

在 Vue 3 中,可以通过配置 vue.config.js 文件来设置 public 目录,它的作用与 assets 目录类似,用来存放静态资源文件。但是,与 Vue 2 不同的是,public 目录下的文件不会被打包,而是会直接复制到输出目录下

37.单页应用如何提高加载速度?

  • 使用代码分割:将代码拆分成小块并按需加载(懒加载),以避免不必要的网络请求和减少加载时间。
  • 缓存资源:利用浏览器缓存来存储重复使用的文件,例如 CSS 和 JS 文件、图片等。
  • 预加载关键资源:在首次渲染之前,先提前加载关键资源,例如首页所需的 JS、CSS 或数据,以保证关键内容的快速呈现。
  • 使用合适的图片格式:选择合适的图片格式(例如 JPEG、PNG、WebP 等),并根据需要进行压缩以减少文件大小。对于一些小图标,可以使用 iconfont 等字体文件来代替。
  • 启用 Gzip 压缩:使用服务器端的 Gzip 压缩算法对文件进行压缩,以减少传输时间和带宽消耗。
  • 使用 CDN:使用内容分发网络(CDN)来缓存和传递文件,以提高文件的下载速度和可靠性。
  • 优化 API 请求:尽可能地减少 API 调用的数量,并使用缓存和延迟加载等技术来优化 API 请求的效率。
  • 使用服务器端渲染:使用服务器端渲染(SSR)来生成 HTML,以减少客户端渲染所需的时间和资源。但需要注意,SSR 也可能增加了服务器的负担并使网站更复杂。

38.Vue父组件调用子组件的方法

vue中如果父组件想调用子组件的方法,可以在子组件中加上ref,然后通过this.$refs.ref.method调用

<child ref="child"></child>
调用:this.$refs.child.子组件方法
  • 1
  • 2

39.vue3中dom获取,ref在组件上使用

<template>
  <div class="ref">
    <h3>ref使用:</h3>
    <input type="text" ref="input" /> //  ref="input" 需要和 const input = ref(null); 相对应
  </div>
</template>

<script setup>
import { reactive, ref, createApp, onMounted } from "vue";

let state = reactive({ text: "信息按钮" });
// 同名的 input来进行获取节点
const input = ref(null);
onMounted(() => {
  if (input.value) {
    input.value.focus();
  }
});
</script>
<style scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

40.渐进式框架理解

渐进式: 可以理解为没有多做职责之外的事

个人理解:主张最少的,一开始仅基于基础框架构建,随着需求不断扩充

41.页面初始化闪烁

产生原因:当网速较慢,vue.js文件还没有加载完时,在页面上会显示{{message}}的字样,知道vue创建实例,编译模板时,dom才会被替换,所以这个过程屏幕是闪动的。

所以解决这个问题,需要在style样式中设置【v-cloak】{display:none}。在一般情况下,v-clock是一个解决初始化慢导致页面闪动的最佳实践,对于简单的项目很实用。

但是在具有工程化的项目里,比如使用了webpack和vue-router的项目中,html结构只是一个空的div元素,剩余的内容都是由路由去挂载不同的组件完成的,所以不需要v-cloak。

42.vue属性名和method名称一致出现什么问题

vue2中, 这个属性会覆盖掉 methods 中的方法。也就是说,这个方法将无法被正确调用。

vue3中,报错

43.class和style如何动态绑定

class 与 style 动态绑定一般通过对象或者数组来实现

对象写法:适用于要绑定的样式名字样式确定,但动态决定用不用。

数组写法:适用于要绑定的样式名字样式不确定。

<div v-bind:class="{ active: isActive }"></div> //对象写法
<div v-bind:class="[activeClass, errorClass]"></div> //数组写法
  • 1
  • 2

44.vue遇到的坑

  • data必须是一个函数,而不是一个对象
  • vue管理的函数不要写成箭头函数
  • 添加属性页面不刷新
  • 子路由path不需要添加**/**,path=‘new’

45.v-if和v-for 优先级

实践中不管是vue2或者vue3都不应该把v-if和v-for放在一起使用。

在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时, v-for 会优先作用。

在 vue 3.x 中, v-if 总是优先于 v-for 生效。

vue2中v-for的优先级是高于v-if的,放在一起,会先执行循环在判断条件,并且如果值渲染列表中一小部分元素,也得再每次重渲染的时候遍历整个列表,比较浪费资源。

vue3中v-if的优先级是高于v-for的,所以v-if执行时,它调用相应的变量如果不存在,就会导致异常

46.vue核心原理

数据驱动,组建系统

47.vue自带动画组件, transition

组件是 Vue 提供的用于包裹需要动画效果的元素组件。使用组件可以方便地实现元素的进入和离开动画效果。

<template>
  <div>
    <button @click="visible = !visible">Toggle</button>
    <transition name="fade">
      <p v-if="visible">Hello, World!</p>
    </transition>
  </div>
</template>

<script>
export default {
  data() {
    return {
      visible: false
    }
  },
}
</script>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

48.vue-loader工作原理

  1. 将一个 .vue 文件 切割成 templatescriptstyles 三个部分。
  2. template 部分 通过 compile 生成 renderstaticRenderFns
  3. 获取 script 部分 返回的配置项对象 scriptExports
  4. styles 部分,会通过 css-loadervue-style-loader, 添加到 head 中, 或者通过 css-loaderMiniCssExtractPlugin 提取到一个 公共的css文件 中。
  5. 使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回 构建vue组件需要的配置项对象 - options, 即 {data, props, methods, render, staticRenderFns…}

49.vue的diff算法

diff整体策略为:深度优先,同层比较

  • 当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁

  • 通过isSameVnode进行判断,相同则调用patchVnode方法

  • patchVnode

    做了以下操作:

    • 找到对应的真实dom,称为el
    • 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
    • 如果oldVnode有子节点而VNode没有,则删除el子节点
    • 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
    • 如果两者都有子节点,则执行updateChildren函数比较子节点
  • updateChildren

    主要做了以下操作:

    • 设置新旧VNode的头尾指针
    • 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作

50.vue和jquery区别

设计理念

Vue.js 是一个现代化的JavaScript框架,专注于构建大型的、可维护的Web应用程序。Vue.js 的核心是组件化,它提供了一种将页面分解成独立、可重用的组件的方式,并且能够非常容易地管理这些组件之间的依赖关系。同时,Vue.js 还内置了状态管理、路由、构建工具等功能,使得构建复杂的 Web 应用程序更加容易。

而 jQuery 则是一个早期的 JavaScript 库,主要关注的是 DOM 操作和处理事件。它的设计理念是将 JavaScript 代码尽可能地简单化,使得使用者可以很容易地完成一些常见的操作(如选择元素、修改样式、处理事件等)。在 jQuery 中,通过链式调用和函数式变成的设计,可以使得代码变得非常简洁易读。

用途

Vue.js 主要用于构建大型的、复杂的 Web 应用程序,它提供了诸如组件化、状态管理、路由等功能,非常适合构建单页面应用(SPA)。

而 jQuery 则更多地用于简化 DOM 操作和事件处理,它适用于编写小型的 Web 应用程序或较为简单的交互效果。同时,由于 jQuery 在浏览器兼容性、性能等方面的优势,它也被广泛应用于一些成熟的网站和CMS系统中。

51.说说你对 SPA 单页面的理解,它的优缺点分别是什么?

SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。

  • 优点:
    用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
    基于上面一点,SPA 相对对服务器压力小;
    前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
  • 缺点:
    初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统加载,部分页面按需加载;
    前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
    SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

52. 怎样理解 Vue 的单向数据流?

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

53. 父组件可以监听到子组件的生命周期吗?

比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
  this.$emit("mounted");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('父组件监听到 mounted 钩子函数 ...');
},

//  Child.vue
mounted(){
   console.log('子组件触发 mounted 钩子函数 ...');
},    

// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。

54.Vue3.0 性能提升主要是通过哪几方面体现的

  • diff算法优化
  • 静态提升: Vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用
  • 移除一些不常用的API,再重要的是Tree shanking
  • 响应式系统

55.什么是 MVVM?比之 MVC 有什么区别?什么又是 MVP ?

MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。 用户与页面产生交互时Controller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对 Model 的修改,然后 Model 层再去通知 View 层更新。

MVVM 模式中的 VM,指的是 ViewModel, 它通过双向的数据绑定,将 View 和 Model 的同步更新给自动化了。当 Model 发生变化的时候,ViewModel 就会自动更新;ViewModel 变化了,View 也会更新。

MVP 模式 ,View 层的接口暴露给了 Presenter 因此我们可以在 Presenter 中将 Model 的变化和 View 的变化绑定在一起,以此来实现 View 和 Model 的同步更新

56.vue中hook和react中hook区别

在React中,hook是一种函数,它可以让你在函数组件中添加state、effect等功能。 React 中的hook有useState、useEffect、useContext等。使用hook可以避免使用类组件时可能会出现的繁琐的生命周期方法、this等问题。

在Vue中,hook被称为生命周期钩子函数,它们是在组件实例化过程中自动调用的回调函数。 Vue中的生命周期钩子函数包括beforeCreate、created、beforeMount、mounted等。它们可以用于控制组件的生命周期,以及在组件生命周期特定阶段执行特定的操作。

57.Redux和Vuex的区别

redux是一个范用的js库,vuex是专门服务vue的

相同点:

  1. state共享数据
  2. 流程一致:定义全局state,触发,修改state
  3. 原理相似,通过全局注入store。

不同点:

  1. Vuex定义了state,getter、mutation、action,module五个对象;redux定义了state、reducer、action;
  2. Vuex触发方式有两种commit同步和dispatch异步;redux同步和异步都使用dispatch;
  3. Vuex中action有较为复杂的异步ajax请求;redux中action中可简单可复杂,简单就直接发送数据对象({type:xxx, your-data}),复杂需要调用异步ajax(依赖redux-thunk插件)。
  4. Redux使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改;
  5. Redux在检测数据变化的时候,是通过diff的方式比较差异的,而Vuex其实和Vue的原理一样,是通过getter/setter来比较的。

58.vue服务端渲染(SSR),解决了哪些问题?

Vue服务端渲染(SSR)通过在服务器上预先生成Vue组件的HTML字符串,并将其发送到客户端,以实现更快的页面加载速度、更好的搜索引擎优化和更好的用户体验。服务端渲染解决了许多SPA(Single Page Application)应用程序中存在的问题,例如:

  1. SEO(搜索引擎优化)问题:由于传统的SPA应用程序是在浏览器中构建的,因此搜索引擎无法正确地索引它们的内容。使用Vue SSR,可以在服务器上呈现HTML字符串并向搜索引擎提供更好的友好的页面。
  2. 性能问题:SPA应用程序需要大量的JavaScript代码来初始化应用程序并交互。这可能导致页面加载时间缓慢,用户体验较差。使用Vue SSR,可以在浏览器中更快地呈现初始HTML的完整标志,并在其中嵌入必要的JavaScript。这样可以加快页面加载速度,并提高用户体验。
  3. 首屏渲染问题:传统的SPA应用程序在首次加载时可能会需要大量时间才能呈现第一个屏幕,直到JavaScript代码完成下载并执行。使用Vue SSR,可以在服务器上呈现组件,并将其作为HTML字符串发送到客户端,从而实现快速呈现首屏的目标。

59.Vue 3.0中Treeshaking特性是什么,并举例进行说明?

Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术

Tree shaking是基于ES6模板语法(importexport),主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量

Tree shaking无非就是做了两件事:

  • 编译阶段利用ES6 Module判断哪些模块已经加载
  • 判断那些模块和变量未被使用或者引用,进而删除对应代码

作用:

  • 减少程序体积(更小)
  • 减少程序执行时间(更快)
  • 便于将来对程序架构进行优化(更友好)

60. 虚拟 DOM 的优缺点?

优点:

  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

缺点:

  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

61. 虚拟 DOM 实现原理?

虚拟 DOM 的实现原理主要包括以下 3 部分:

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
  • diff 算法 — 比较两棵虚拟 DOM 树的差异;
  • pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

62. Vue 中的 key 有什么作用?

key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。
Vue 的 diff 过程可以概括为:oldCh 和 newCh 各有两个头尾的变量 oldStartIndex、oldEndIndex 和 newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有4种比较方式:newStartIndex 和oldStartIndex 、newEndIndex 和 oldEndIndex 、newStartIndex 和 oldEndIndex 、newEndIndex 和 oldStartIndex,如果以上 4 种比较都没匹配,如果设置了key,就会用 key 再进行比较,在比较的过程中,遍历会往中间靠,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较。
所以 Vue 中 key 的作用是:key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速!

  • 更准确:因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。
  • 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,源码如下:
function createKeyToOldIdx (children, beginIdx, endIdx) {
  let i, key
  const map = {}
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key
    if (isDef(key)) map[key] = i
  }
  return map
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

62. Object.defineProperty怎么用, 三个参数?,有什么作用啊?

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

     obj:需要定义属性的对象
     prop:需要定义的属性
     {}:要定义或修改的属性描述符。
	     value: "18",         // 设置默认值 (与 get() 互斥)
	     enumerable: true,    //这一句控制属性可以枚举 enumerable 改为true 就可以参与遍历了   默认值false
	     writable: true,      // 该属性是否可写   默认值false (与 set() 互斥)
	     configurable: true,  // 该属性是否可被删除   默认值false
	      get // 当有人读取 prop 的时候  get函数就会调用,并且返回就是 sss 的值
	      set // 当有人修改 prop 的时候  set函数就会调用, 有个参数这个参数就是修改后的值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

63.reactive与ref的区别?

从定义数据角度对比:

  • ref用来定义:基本类型数据

  • reactive用来定义对象(或数组)类型数据

    备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。

从原理角度对比:

  • ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
  • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。

从使用角度对比:

  • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
  • reactive定义的数据:操作数据与读取数据:均不需要.value。

64.v-on可以监听多个方法吗?

可以一个元素绑定多个事件的两种写法

<a v-on='{click:DoSomething,mouseleave:MouseLeave}'>doSomething</a>
<button @click="a(),b()">点我ab</button>
  • 1
  • 2

65.vue3中如何获取refs,dom对象的方式?vue2中如何使用?

vue3:

(1) setup函数方法内,获取单个ref属性绑定的dom元素:先定义一个空的响应式数据ref定义的,你想获取哪个dom元素,在该元素上使用ref属性绑定该数据即可,通过ref.value即可获取到dom节点

(2) 获取多个ref属性绑定的dom元素。使用ref绑定一个函数,在函数里把dom添加到数组里面

//vue2
<h3 ref="myref">myref</h3>

//获取
this.$refs.myref
  • 1
  • 2
  • 3
  • 4
  • 5

66.shallowReactive和shallowRef的区别

(1) shallowReactive:只处理对象最外层的响应式(浅响应式)

(2) shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。

(3) 应用场景:

​ ① 如果有一个对象数据,结构比较深,但变化时候,只是外层属性变化,使用shallowReactive。

​ ② 如果有一个对象数据,后续功能不会修改改对象中的属性,而是生成新的对象来替换,使用shallowRef。

67.provide与inject如何使用

(1) 父子组件传参可以通过props和emit来实现,但是当组件的层次结构比较深时,props和emit就没什么作用了。vue为了解决这个提出了Provide / Inject;provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量

(2) provide需要先引入,我们将需要传递给下级组件的变量通过provider(‘传输key’,变量)

(3) Inject,下级组件通过变量方式接收,person= inject(‘传输key’)

68.toRaw 与 markRaw是什么作用?

(1) toRaw :将一个由reactive生成的响应式对象转化为普通对象

使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新.

(2) markRaw:标记一个对象,使其永远不会再成为响应式对象。

应用场景:有些值不应被设置为响应式的,例如复杂的第三方类的库,当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0gRb8BE4-1686967105050)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685349361040.png)]

69.Readonly和shallowReadonly理解

readonly:让一个响应式数据变为只读的(深只读),readonly是一个函数,他会接收一个响应式的数据

shallowReadonly:让一个响应式数据变为只读的(浅只读),shallowReadonly只限制对象中的第一层数据(不能改动,如:salary),但是嵌套的深层次的value属性值 是可以更改的,我们点击更改按钮测试就能发现,被shallowReadonly包裹的对象的深层次值改变了。

70.toref和torefs区别

toReftoRefs 可以用来复制 reactive 里面的属性然后转成 ref,而且它既保留了响应式,也保留了引用

toref(变量,属性),torefs(整个变量)

区别:

  • 在插值表达式中{{}}:
    • 访问 toRefs 的值,需要带上 .value 如果不带上,就会出现双引号 {{user.name.value}}
    • 访问 toRef 的值,不需要带上 .value {{user.name}}
  • 转换属性:
    • toRef: 复制 reactive 里的单个属性并转成 ref
    • toRefs: 复制 reactive 里的所有属性并转成 ref

71.学习 EventBus

首先,在你的项目中创建一个 eventBus.js 文件,并定义一个空的 EventBus 对象:

import Vue from 'vue';
export const EventBus = new Vue();
  • 1
  • 2

发送事件

import { EventBus } from './eventBus.js';

// 发送名为 'myEvent' 的事件
EventBus.$emit('myEvent', data);
  • 1
  • 2
  • 3
  • 4

接收事件

import { EventBus } from './eventBus.js';

EventBus.$on('myEvent', (data)=>{});
  • 1
  • 2
  • 3

取消监听

EventBus.$off('myEvent');
  • 1

72.vue2过滤器(vue3取消)

filter 过滤器是一种很常用的功能,它可以用于对数据进行格式化、排序、筛选等操作。在使用过程中,我们只需要在模板表达式中使用管道符 |,并将要使用的过滤器的名称作为参数传递进去即可。

全局过滤器:Vue.filter(‘过滤器名称’,function(){})

局部过滤器:filter选项

filters: {
    //filterName过滤器名,value是'|'之前的数据
    filterName(value) {
      if (!value) return '';
      return '你好'+value.toString()
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

73. vue可以通过计算属性监听计算属性吗

答案:不可以

计算属性依赖于其他属性值,所以我们可以在计算属性中监听这些属性值的变化,并执行一些相关的操作 。 但是,计算属性无法直接监听另一个计算属性的变化,因为一个计算属性的值不是响应式的,它依赖的属性值发生变化时只有它自己才会重新计算,而不会触发其他计算属性的更新


六、TypeScript篇

1.TypeScript基本数据类型

原始数据类型:

  • boolean 布尔值
  • number 数值
  • string 字符串
  • null 空值
  • undefined 未定义
  • Symbol (ES6 中的新类型)

非原始数据类型:

  • 数组 arr: number[] arr: Array

  • Tuple 元祖 x: [string, number]

  • enum 枚举

enum Color {Red, Green, Blue};
let c: Color = Color.Blue;//默认情况下,从 0 开始为元素编号。
console.log(c);    // 输出 2

enum Person {
 name = "NAME",
 age = "AGE",
 love = "LOVE",
 hobby = "HOBBY",
}
console.log(Person.name); // NAME
console.log(Person.hobby); // HOBBY
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • never 永不存在的值的类型

  • void

//void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void。
function hello(): void {
   alert("Hello ts");
}
  • 1
  • 2
  • 3
  • 4
  • any 任意类型

  • 联合类型

//联合类型(Union Types)表示取值可以为多种类型中的一种。
let num: string | number;
num = "seven";
num = 7;
  • 1
  • 2
  • 3
  • 4
  • 函数类型
  • unknown 表示一个未知的类型,使用unknown标注的变量和参数必须经过类型检查和转换后才能使用。

2.void和undefined

let unde: void = undefined;
let nu: void = null;

let un: undefined = undefined;
let nu: null = null;

//与 void 的区别是,undefined是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量

let num: number = undefined;

let un: undefined;
let num2: number = un;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.TypeScript类修饰符

TypeScript支持访符 public,private 和 protected,它们决定了类成员的可访问性。

public(公共):所有定义成public的属性和方法都可以在任何地方进行访问。

private(私有):所有定义成private的属性和方法都只能在类定义内部进行访问。

protected(受保护): 该类及其子类的所有成员都可以访问它们。 但是该类的实例无法访问

4.如何定义一个数组,它的元素可能是字符串类型,也可能是数值类型

//通过不同方式使用联合类型写法  |

// 方法1:
let arr1: (number | string)[] = [1]
arr1.push(1)
arr1.push('3')

// 方法2:
let  arr2 : Array<string | number> = [1, '2']
arr2.push(1)
arr2.push('3')

// 方法3:
type newType = number|string
let arr3:newType []= [3]
arr3.push(1)
arr4.push('5')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5.TypeScript接口

接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。

//接口定义 interface
interface interface_name { 
}
  • 1
  • 2
  • 3
//以下实例中,我们定义了一个接口 IPerson,接着定义了一个变量 customer,它的类型是 IPerson。
//customer 实现了接口 IPerson 的属性和方法。
interface IPerson { 
    firstName:string, 
    lastName:string, 
    sayHi: ()=>string 
} 
 
var customer:IPerson = { 
    firstName:"Tom",
    lastName:"Hanks", 
    sayHi: ():string =>{return "Hi there"} 
} 
 
console.log("Customer 对象 ") //Customer 对象
console.log(customer.firstName) //Tom
console.log(customer.lastName)//Hanks
console.log(customer.sayHi()) //Hi there
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

6.TypeScript对象和TypeScript接口的区别

对象:对象是TS中一种数据类型,可以用来存储多个数据属性和方法,并且可以通过对象字面量或者构造函数来创建实例

接口:接口是TS中定义数据结构的规范,主要用于描述对象的形状,即对象应该包含哪些属性和方法,但不提供实现。接口可以作为一个契约,确保其他代码符合其规范

//对象
let person = {
  name: "Tom",
  age: 18,
  sayHi: function() {
    console.log("Hi");
  }
};

console.log(person.name); // Tom
person.sayHi(); // Hi

//接口
interface Person {
  name: string;
  age: number;
  sayHi(): void;
}

let person: Person = {
  name: "Tom",
  age: 18,
  sayHi() {
    console.log("Hi");
  }
};

console.log(person.name); // Tom
person.sayHi(); // Hi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

类型别名及类型符号csdn详情参考

7.TypeScript类型别名

上述介绍了ts中的数据类型和接口,但是在开发过程中 不可避免的会遇到各种复杂类型 , 有些数据类型更灵活、复杂,那么此时,类型别名是一种非常有用的工具,它可以帮助我们简化代码,提高代码的可读性和可维护性

基本用法: type 类型名 = 类型值

type Name = string;
type Age = number;
type Person = {
  name: Name;
  age: Age;
  sayHi(): void;
};

let person: Person = {
  name: "Tom",
  age: 18,
  sayHi() {
    console.log("Hi");
  }
};

console.log(person.name); // Tom
person.sayHi(); // Hi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

8.TypeScript字面量类型

字面量类型(Literal Types)用来表示具体的字面量值,包括字符串、数字、布尔值等。它们可以作为类型注解的一部分,用来限制变量、函数参数、函数返回值等的取值范围

  • 数字字面量,字符串字面量,布尔字面量,空值字面量,枚举字面量

    //数字字面量
    type Num = 10
    const num: Num = 10
    const num2: Num = 20 // 抛错,不能将20赋值给类型10
    
    //字符串字面量
    type Str = "a"
    const num: Str = "a"
    
    //布尔字面量
    type Bool = false
    const bool: Bool = false
    
    //空值字面量
    type Void = void;
    const isNull: Void = null
    const isUndefined: Void = undefined
    const isVoid: Void = void 0
    
    //枚举字面量
    enum Color {
        Red = 1,
        Green,
        Blue
    }
    type colorBlue = Color.Blue
    const blue: colorBlue = 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

9.TypeScript类型符号

TypeScript中的类型符号是用来声明变量类型的符号,主要有以下几种:

  1. ::用于声明变量的类型,例如:let a: number = 10; 表示声明一个名为a的变量,并将其类型标注为number。
  2. ?:用于表示某个属性或参数是可选的,例如:interface Person { name: string; age?: number; } 表示Person接口的age属性是可选的。
  3. []:用于表示数组类型,例如:let arr: number[] = [1, 2, 3]; 表示声明一个名为arr的数组,其中元素类型为number。
  4. ():用于表示函数类型,例如:function add(a: number, b: number): number { return a + b; } 表示声明一个名为add的函数,其中参数a和b的类型均为number,返回值类型也为number。
  5. |:用于表示联合类型,例如:let c: number | boolean = 10; 表示声明一个名为c的变量,其类型为number或者boolean。
  6. &:用于表示交叉类型,例如:interface A { a: number; } interface B { b: string; } type C = A & B; 表示定义一个名为C的交叉类型,它同时包含A和B两个接口的属性和方法

10.TypeScript交叉类型

交叉类型(Intersection Types)可以用来将多个类型合并为一个类型。交叉类型使用且符号&进行连接两个或多个类型;值得注意的是交叉类型一般使用于对象定义这种复杂的数据类型,如果使用交叉类型定义基础类型,则会转换为never类型,因为一个类型不可能同时兼备两种基础类型

& 连接的是简单联合类型,则产生的新类型是 & 符号两边类型的公有类型。

//交叉基础类型,错误示范
type str = string
type num = number
type StrAndNum = str & num // never类型

//正确示范
type information = {
    name: string
    age?: number  //?是可选类型,可以下放交叉不使用
}
type information2 = {
    readonly address: string
}
 
type user = information & information2
 
const whiteDog: WhiteDog = {
    name: "lc",
    address: "中国",
}

//` & 连接的是简单联合类型
type A = string | number
type B = string[] | number
// C是A和B共有的类型,number类型
type C = A & B
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

11.泛型对象

泛型:使用尖括号<>来声明类型参数 (可以有多个)来表示暂时未知的类型,在实际声明变量时传入相应的类型 (或者由TS自动推论) 来替换相应出现该类型参数的地方,从而将抽象的、未知的类型替换为具体的、已知的类型。一个类型参数指代一种类型,例如<T,K,U,…>分别指代一种暂时未知的类型。将泛型用于定义对象类型,便得到了泛型对象。

// 类型T代表一种暂时未知的类型
interface PersonInfo<T> {
  info: T
}
// 传入类型变量string,这时候string就会在相应的地方替换原来的T
let p1: PersonInfo<string> = {
  info: 'cc'
}

let p2: PersonInfo<number> = {
  info: 18
}

let p3: PersonInfo<'男' | '女'> = {
  info: "男"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

泛型同样可在类型别名中使用。而类型别名除了定义对象类型之外,还能用泛型来定义各种其它类型。因此,我们可以使用泛型嵌套来定义更为复杂的类型结构

12.类型断言

类型断言(Type Assertion)是一种显式地告诉编译器变量的类型的方式,它允许我们手动指定一个变量的类型,从而绕过TypeScript编译器对该变量类型的检查

//断言两种方式,<>和as

let str: unknown
const len: number = (<string>str).length

let str: unknown
const len: number = (str as string).length
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

个人理解:事先定义了一个变量为它设置了类型,但是在其它场景需要这个变量为其它类型为了避免报错通过断言指定它为需求类型

13. unknown 类型

类型unknown表示一个未知的类型。与any类型不同,使用unknown标注的变量和参数必须经过类型检查和转换后才能使用。

应用场景:

  • 当我们不知道某个变量的类型时,在某些情况下可以先把它标注为unknown类型,并在使用前进行类型检查或类型转换。
  • 当我们编写一些通用的函数或库时,为了避免与不同的代码库之间发生类型冲突,可以使用unknown类型来定义变量和参数。
function processValue(value: unknown) {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  } else if (typeof value === "number") {
    console.log(value.toFixed(2));
  }
}

let val1: unknown = "hello";
processValue(val1); // 输出HELLO

let val2: unknown = 3.1415;
processValue(val2); // 输出3.14

let val3: unknown = true;
processValue(val3); // 编译时错误:boolean类型不能转换为string或number类型
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

从上面的例子中可以看出,如果不进行类型检查或类型转换,使用unknown类型的变量会导致编译时错误。但是,通过类型检查和转换,我们可以安全地使用这个变量并避免类型错误。

14.函数重载

函数名称相同,但是参数的个数或者类型不同。

// 函数的定义
function add(num1: number, num2: number): number;
function add(num1: string, num2: string): string;

// 函数的实现
function add(num1: any, num2: any): any {
    return num1 + num2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

15.抽象类

通过abstract定义抽象类

在 TypeScript 中,抽象类是一种特殊的类,它本身不能被实例化,而只能被继承。抽象类可以包含抽象方法(即只有方法签名,没有实现),用于定义一些基本的行为或约束子类必须实现的方法,以及普通的具体方法,用于提供一些默认的实现。

// 不可以 new Animal 只能继承抽象类
abstract class Animal {
  abstract makeSound(): void;
  move(distanceInMeters: number = 0) {
    console.log(`Animal moved ${distanceInMeters}m.`);
  }
}

class Dog extends Animal {
  makeSound() {
    console.log("Woof! Woof!");
  }
}

let dog = new Dog();
dog.makeSound(); //  "Woof! Woof!"
dog.move(10); // "Animal moved 10m."

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

16.类型守卫,typeof 以及 instanceof

typeof 类型守卫:使用 typeof 运算符可以判断一个变量的类型是 string、number、boolean、symbol 或 undefined。

instanceof 类型守卫:使用 instanceof 运算符可以判断一个变量是否为指定类的实例。它的使用方法是在检测对象的同时指定一个构造函数作为比较对象

//typeof
function example(value: string | number) {
  if (typeof value === "string") {
    console.log(`The value is a string: ${value}`);
  } else {
    console.log(`The value is a number: ${value}`);
  }
}
example("hello"); // Output: "The value is a string: hello"
example(42); // Output: "The value is a number: 42"

//instanceof
class MyClass {}
function example(input: MyClass | string) {
  if (input instanceof MyClass) {
    console.log("The input is an instance of MyClass.");
  } else {
    console.log(`The input is a string: ${input}`);
  }
}
example(new MyClass()); // Output: "The input is an instance of MyClass."
example("hello"); // Output: "The input is a string: hello"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

17.TypeScript 编译上下文

在 TypeScript 中,编译上下文是指编译器对源代码进行类型检查和转换时所使用的环境和规则

编译上下文可以包含以下几个方面:

  1. 编译选项:编译器可以通过命令行参数或 tsconfig.json 文件等方式配置各种编译选项,包括输出目录、模块解析方式、生成的 JavaScript 版本等。
  2. 类型检查:编译器会对源代码进行类型检查,以捕获可能的类型错误和提供更准确的类型推断。类型检查过程中涉及到类型系统、类型注解、类型推断等概念。
  3. 类型转换:在编译过程中,TypeScript 会将源代码中使用的语言特性(如类、接口、泛型、枚举、命名空间等)转换成相应的 JavaScript 代码。这个过程中,编译器还会进行一些优化和调整。
  4. 声明文件处理:TypeScript 支持使用声明文件来描述 JavaScript 库和模块的类型信息,以提高与第三方库的兼容性和开发效率。编译器会自动搜索项目中的声明文件,或者对于没有声明文件的库,也可以通过第三方工具自动生成。
  5. 模块解析:在编译过程中,编译器需要解析模块之间的依赖关系,以便正确地生成相应的 JavaScript 代码文件。模块解析涉及到模块路径、模块别名、自定义解析等问题。

18.tsconfig.json

tsconfig.json 是一个用于配置 TypeScript 编译器的配置文件。通过这个配置文件,可以指定编译器所使用的规则和选项,以实现自定义编译过程和调整输出结果

{
  "compilerOptions": {
    /* 基本选项 */
    "target": "es5",                       /* 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT' */
    "module": "commonjs",                  /* 指定模块化代码生成方式: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext' */
    "lib": ["es6", "dom"],                 /* 指定要包含在编译中的库文件,默认为所有支持的库 */
    "outDir": "./dist",                    /* 指定输出目录 */
    "rootDir": "./src",                    /* 指定源代码目录 */
  
    /* 详细选项 */
    "strict": true,                        /* 启用所有严格类型检查选项 */
    "noImplicitAny": true,                 /* 在表达式和声明上有隐含的 any 类型时报错 */
    "strictNullChecks": true,              /* 启用严格的 null 检查 */
    "noImplicitThis": true,                /* 当 this 表达式值为 any 类型的时候,生成一个错误 */
    "alwaysStrict": true,                  /* 以严格模式检查每个模块,并在模块内部启用 "use strict" */
  
    /* 配置文件扩展选项 */
    "resolveJsonModule": true,             /* 允许导入 .json 模块 */
    "esModuleInterop": true,               /* 自动生成命名空间导入 (import * as module from "module") */
    "skipLibCheck": true                    /* 跳过对声明文件的检查 */
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

19.TypeScript 和JavaScript区别

js没有重载概念,ts有可以重载

ts增加了接口interface、泛型、类、类的多态、继承等

ts对比js基础类型上,增加了 void/never/any/元组/枚举/以及一些高级类型

选择学习

  1. 类型系统:TS 是一种拥有静态类型检查的编程语言,支持在代码中明确指定变量的数据类型、声明函数的输入和输出类型、定义接口和类等。而 JS 则是一种动态类型的语言,变量类型是在运行时动态确定的。
  2. 编译方式:TS 是一种编译型语言,需要通过编译器将 TS 代码转换为等价的 JS 代码才能在浏览器或者 Node.js 中执行。而 JS 是一种解释型语言,直接由运行时解释执行。
  3. 扩展语法:TS 支持 ECMAScript 标准中定义的所有语法,并且还提供了一些自己的扩展语法,例如枚举类型、泛型、元组类型等。JS 则不支持所有扩展语法,并且在新标准发布前需要等待浏览器厂商的实现或者使用 polyfill 进行补丁。
  4. 开发工具:TS 具备良好的 IDE 集成、语法高亮、代码提示、错误检查等功能,开发体验更加友好。JS 的开发工具则相对简单,主要是一些文本编辑器和浏览器控制台。
  5. 生态环境:TS 是由微软开发并维护的项目,有着全球范围内的活跃社区和丰富的第三方库。JS 则更加开放和自由,生态环境更加广泛和多样化。

七、React篇

1.react理解

  • React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 ,是渐进式框架,采用mvc架构
  • 特性: JSX 语法 , 单向数据绑定 , 虚拟 DOM , 声明式编程 ,组件化开发

2.react-router 里的 标签和 标签有什么区别?

  • react-router 接管了其默认的链接跳转行为,与传统的页面跳转有区别的是,Link 的 “跳转” 行为只会触发相匹配的对应的页面内容更新,而不会刷新整个页面。
  • link做了哪些事:1.有onclick就执行onclick,2.click的时候阻止a标签默认事件,3.根据跳转href用history跳转,此时只是链接变了,并没有刷新页面

3.React Jsx转换成真实DOM过程?

  • 首先我们知道Jsx代码是不会被浏览器识别的,最终都会转化为 React.createElement 形式,babel实现这个过程
  • createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
  • ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM

4.React Router的理解,原理?常用的Router组件有哪些?

  • 路由的本质就是页面的URL发生改变时,页面的显示结果可以根据URL的变化而变化,但是页面不会刷新
  • react-router主要分成了几个不同的包(这一块先不写了)
  • 常用router组件:
    • BrowserRouter、HashRouter : 路由模式history,hash
    • route: Route用于路径的匹配,然后进行组件的渲染
    • Link、NavLink: 通常路径的跳转是使用Link组件 NavLink是在Link基础之上增加了一些样式属性,例如组件被选中时,发生样式变化 ( activeStyle , activeClassName )
    • redirect:路由重定向
    • switch: swich组件的作用适用于当匹配到第一个组件的时候,后面的组件就不应该继续匹配

5.react生命周期

  • 组件挂载时
    当组件实例被创建并插入DOM时,其生命周期调用顺序如下:

    constructor()
    static getDerivedStateFromProps()
    render()
    componentDidMount()

  • 组件更新时
    当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:

    static getDerivedStateFromProps()
    shouldComponentUpdate()
    render()
    getSnapshotBeforeUpdate()
    componentDidUpdate()

  • 组件卸载时
    当组件从DOM中移除时会调用如下方法

    componentWillUnmount()

6.react新生命周期取代了哪些?为什么?

React 新的生命周期方法主要是为了支持 Fiber 架构中的三个新概念而设计的: fiber节点,异步渲染,可中断性

  • getDerivedStateFromProps(静态方法) 取代了componentWillMount和 componentWillReceiveProps

  • getSnapshotBeforeUpdate 取代了componentWillUpdate

  • getDerivedStateFromProps 中禁止了组件去访问 this.props, 由于 this.props 可能在任何时刻发生变化,所以计算出来的 state 对象可能会与旧的 state 对象相同,从而导致状态更新无效和不必要的组件重新渲染。 在 getDerivedStateFromProps 方法中应该始终使用参数中的 nextProps,而不是 this.props。这样可以保证组件状态的计算是基于最新的 props,从而避免了状态更新无效和渲染性能的问题。

  • getSnapshotBeforeUpdate 方法是在组件的 render 方法被调用后,在更新 DOM 之前被调用的 ,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素信息是可以保证与componentDidUpdate 中一致的。

7.Fiber架构的理解?解决了什么问题?

在 React 16 之前,VirtualDOM 的更新采用的是Stack架构实现的,也就是循环递归方式。不过,这种对比方式有明显的缺陷,就是一旦任务开始进行就无法中断,如果遇到应用中组件数量比较庞大,那么VirtualDOM 的层级就会比较深,带来的结果就是主线程被长期占用,进而阻塞渲染、造成卡顿现象。

fiber:为了避免出现卡顿等问题,我们必须保障在执行更新操作时计算时不能超过16ms,如果超过16ms,就需要先暂停,让给浏览器进行渲染,后续再继续执行更新计算。而Fiber架构就是为了支持“可中断渲染”而创建的。 解决了react在渲染大量dom节点出现丢帧的问题

React Fiber 与浏览器的交互流程如下图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4G89UyXp-1686967105051)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685850448945.png)]

  • 从架构角度:fiber是对react核心算法的重写(调和过程)
  • 从编码角度:fiber是react内部定义的一种数据结构,是fiber树结构的节点单位,react16新架构下的虚拟dom
  • 主要操作:
    • 为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
    • 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
    • dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行

在 Fiber 架构中,React 将组件的更新过程分为两个阶段:reconciliation 和 commit。其中 reconciliation 阶段主要负责计算出更新后的 Virtual DOM 树,并确定哪些组件需要进行重新渲染,而 commit 阶段则负责将 Virtual DOM 树的变化映射到真实的 DOM 上。

总结:相比传统的Stack架构,Fiber 将工作划分为多个工作单元,每个工作单元在执行完成后依据剩余时间决定是否让出控制权给浏览器执行渲染。 并且它设置每个工作单元的优先级,暂停、重用和中止工作单元。 每个Fiber节点都是fiber tree上的一个节点,通过子、兄弟和返回引用连接,形成一个完整的fiber tree。

8.react有状态组件和无状态组件的理解及使用场景?、

  • 有状态组件
    • 特点:
      • 是类组件
        有继承
        可以使用 this
        可以使用 react 的生命周期
        使用较多, 容易频繁触发生命周期钩子函数, 影响性能
        内部使用 state, 维护自身状态的变化, 有状态组件根据外部组件传入的 props 和自身的 state 进行渲染
    • 使用场景:
      • 需要使用到状态的
        需要使用状态操作组件的(无状态组件的也可以实现新版本 react hooks 也可实现)
    • 总结:
      类组件可以维护自身的状态变量, 即组件的 state, 类组件还有不同的生命周期方法, 可以让开发者能够在组件的不同阶段(挂载、更新、卸载), 对组件做更多的控制。类组件则既可以充当无状态组件, 也可以充当有状态组件。当一个类组件不需要管理自身状态时, 也可称为无状态组件。
  • 无状态组件
    • 特点:
      • 不依赖自身的状态 state
        可以是类组件或者函数组件
        可以完全避免使用 this 关键字(由于使用的是箭头函数事件无需绑定)
        有更高的性能, 当不需要使用生命周期钩子时, 应该首先使用无状态函数组件
        组件内部不维护 state, 只根据外部组件传入的 props 进行渲染的组件, 当 props 改变时, 组件重新渲染
    • 使用场景
      • 组件不需要管理 state, 纯展示
    • 优点:
      简化代码、专注于 render
      组件不需要被实例化, 无生命周期, 提升性能, 输出(渲染)只取决于输入(属性), 无副作用
      视图和数据的解耦分离
    • 缺点:
      无法使用 ref
      无生命周期方法
      无法控制组件的重渲染, 因为无法使用 shouldComponentUpdate 方法, 当组件接受到新的属性时则会重渲染

9. React 的事件合成?

  • 所有事件都是委托在id = root的DOM元素中(网上很多说是在document中,17版本不是了);
  • 在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发;
  • React自身实现了一套事件冒泡捕获机制;
  • React实现了合成事件SyntheticEvent
  • React17版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16版本及之前);
  • 事件一旦在id = root的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;

10.React组件之间如何通信?

  1. 父组件向子组件通讯:
    父组件可以向子组件传入props的方式,向子组件进行通讯。
  2. 子组件向父组件通讯:
    props+回调的方式,父组件向子组件传递props进行通讯,此props为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。
  3. 兄弟组件通信:
    兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递
    例:组件A – 传值 --> 父组件 – 传值 --> 组件B
  4. 跨层级通讯:
    Context 设计⽬的是为了共享那些对于⼀个
    组件树⽽⾔是“全局”的数据,
    使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
    例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过。
  5. 发布订阅者模式:
    发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信。
  6. 全局状态管理工具:
    借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态。

11.React服务端渲染怎么做?原理是什么?

  • 服务端渲染(SSR): 指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程
  • 服务端渲染解决的问题:1.SEO由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面 2.加速首屏加载,解决首屏白屏问题
  • React如何做服务端渲染?
    • 手动搭建SSR框架
    • 使用成熟的SSR框架,如next.js
  • 实现原理:
    • node server 接收客户端请求,得到当前的请求url 路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 propscontext或者store 形式传入组件
    • 然后基于 react 内置的服务端渲染方法 renderToString()把组件渲染为 html字符串在把最终的 html 进行输出前需要将数据注入到浏览器端
    • 浏览器开始进行渲染和节点对比,然后执行完成组件内事件绑定和一些交互,浏览器重用了服务端输出的 html 节点,整个流程结束

12.使用 React hooks 怎么实现类里面的所有生命周期?

  • 在 React 16.8 之前,函数组件也称为无状态组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyoi6A3F-1686967105051)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1682042087354.png)]

13.React事件和原生事件的执行顺序

  • 为什么会有合成事件:
    • 在传统的事件里,不同的浏览器需要兼容不同的写法,在合成事件中React提供统一的事件对象,抹平了浏览器的兼容性差异
    • React通过顶层监听的形式,通过事件委托的方式来统一管理所有的事件,可以在事件上区分事件优先级,优化用户体验。React在合成事件上对于16版本和17`版本的合成事件有很大不同
  • 执行顺序总结:
    • 16版本先执行原生事件,当冒泡到document时,统一执行合成事件,
    • 17版本在原生事件执行前先执行合成事件捕获阶段,原生事件执行完毕执行冒泡阶段的合成事件,通过根节点来管理所有的事件,原生的阻止事件流会阻断合成事件的执行,合成事件阻止后也会影响到后续的原生执行

14.为什么react元素有一个$$type属性?

目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。如果没有 $$typeof 这个属性,react 会拒绝处理该元素。

15.setState 是同步,还是异步的?

  • react18之前:setState在不同情况下可以表现为异步或同步。在Promise的状态更新、js原生事件、setTimeout、setInterval…中是同步的。在react的合成事件中,是异步的。
  • react18之后: setState都会表现为异步(即批处理)。
  • 解释react18之前:
    • 原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

16.如何让 useEffect 支持 async/await?

  • 为什么不支持?
    • effect function 应该返回一个销毁函数(return返回的 cleanup 函数),如果 useEffect 第一个参数传入 async,返回值则变成了 Promise,会导致 react 在调用销毁函数的时候报错
  • useEffect如何支持async/await?
    • 创建一个异步函数(async...await 的方式),然后执行该函数。

17. React 中可以做哪些性能优化?

  • 使用纯组件 – 纯组件是指那些不依赖于外部状态或引用的组件

  • shouldComponentUpdate 优化

  • 不要使用内联函数定义(如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例)

    function MyButton(props) {
      return (
        <button onClick={() => console.log('Button clicked!')}>
          {props.label}
        </button>
      );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 避免使用内联样式属性;

  • 使用 immutable 不可变数据,在我们项目中使用引用类型时,为了避免对原始数据的影响,一般建议使用 shallowCopy 和 deepCopy 对数据进行处理,但是这样会造成 CPU 和 内存的浪费,所以推荐使用 immutable

    • 优点:
      • 降低了可变带来的复杂度
      • 节省内存 ,immutable 使用结构共享尽量复用内存,没有被引用的对象会被垃圾回收
      • 不会有并发问题(因为数据本身不可变)
      • 拥抱函数编程
  • 给子组件设置一个唯一的 key,因为在 diff 算法中,会用 key 作为唯一标识优化渲染

  • 使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;

  • 在函数组件中使用useCallbackuseMemo来进行组件优化,依赖没有变化的话,不重复执行

  • 路由懒加载

18.react 和 vue 有什么区别?

  • 区别:
    • React 的思路是 HTML in JavaScript 通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS
    • Vue 是把 HTML,CSS,JavaScript 组合到一起,用各自的处理方式,Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。
    • React 整体是函数式的思想,在 React 中是单向数据流,推崇结合 immutable 来实现数据不可变。
    • Vue 的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立 Watcher 来监听,当属性变化的时候,响应式的更新对应的虚拟 DOM。
    • React 的性能优化需要手动去做,而Vue的性能优化是自动的,但是Vue的响应式机制也有问题,就是当 state 特别多的时候,Watcher 会很多,会导致卡顿。
  • 共同点:
    • React 与 Vue 存在很多共同点,例如他们都是 JavaScript 的 UI 框架,组件化开发,单项数据流,声明式编程,虚拟dom
  • 优势:
    • React
      • 灵活性和响应性:它提供最大的灵活性和响应能力。
      • 丰富的JavaScript库:来自世界各地的贡献者正在努力添加更多功能。
      • 可扩展性:由于其灵活的结构和可扩展性,React已被证明对大型应用程序更好。
      • 不断发展: React得到了Facebook专业开发人员的支持,他们不断寻找改进方法。
      • Web或移动平台: React提供React Native平台,可通过相同的React组件模型为iOS和Android开发本机呈现的应用程序。
    • Vue
      • 易于使用: Vue.js包含基于HTML的标准模板,可以更轻松地使用和修改现有应用程序。
      • 更顺畅的集成:无论是单页应用程序还是复杂的Web界面,Vue.js都可以更平滑地集成更小的部件,而不会对整个系统产生任何影响。
      • 更好的性能,更小的尺寸:它占用更少的空间,并且往往比其他框架提供更好的性能。
      • 精心编写的文档:通过详细的文档提供简单的学习曲线,无需额外的知识; HTML和JavaScript将完成工作。
      • 适应性:整体声音设计和架构使其成为一种流行的JavaScript框架。
      • 它提供无障碍的迁移,简单有效的结构和可重用的模板。
  • 总结:
    • Vue 的响应式机制也有问题,当 state 特别多的时候,Watcher 会很多,会导致卡顿,所以大型应用(状态特别多的)一般用 React,更加可控。
    • 对于易用性来说,VUE 是更容易上手的,对于项目来说新人更容易接手。

19.React render方法的原理,在什么时候会触发?

原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
触发机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染

20.React Hooks 在使用上有哪些限制?

  • 不要在循环、条件或嵌套函数中调用 Hook;
  • 在 React 的函数组件中调用 Hook。

21.React Hooks概述及常用的Hooks介绍?

Hooks是React 16.8版本引入的新特性,它为函数组件添加了一些类似于类组件中的状态和生命周期方法的功能

  • useState:用于在函数组件中添加状态管理功能。它返回一个由当前状态值和更新函数组成的数组,我们可以通过该数组来获取和更新状态的值。
  • useEffect:用于执行副作用操作,例如订阅事件、修改DOM等。它接受一个函数作为参数,该函数将在每次渲染完成后执行。
  • useContext:用于在组件间共享数据,它接受一个上下文对象作为参数,然后返回该上下文对象中提供的数据。
  • useReducer:用于对复杂状态进行管理。它接受一个reducer函数和初始状态作为参数,并返回一个由当前状态值和dispatch函数组成的数组。
  • useCallback:用于缓存函数以提高性能,类似于React.memo。
  • useMemo:用于缓存计算结果以提高性能,类似于记忆函数。
  • useRef:用于引用DOM节点或保存任意可变值,它返回一个可变的ref对象。

22.说说React生命周期中有哪些坑?如何避免?

  • getDerivedStateFromProps 容易编写反模式代码,使受控组件和非受控组件区分模糊
  • componentWillMountReact 中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount
  • componentWillReceiveProps 同样也被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。
  • shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。
  • componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdatecomponentDidUpdate 改造使用。
  • 如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug
  • 如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。

23.说说Real diff算法是怎么运作的?

  • Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,将需要内容局部更新
  • Diff算法遵循深度优先,同层比较的原则
  • reactdiff算法主要遵循三个层级的策略:
    tree层级:DOM节点的跨层级操作不做优化,只对相同层节点进行比较,只有删除创建操作,没有移动操作
    conponent 层级:如果是同一类的组件,则会继续往下进行diff运算,如果不是则直接删除组件下的所有子节点,创建新的
    element 层级:对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识,通过key知道节点的变化,移动旧集合节点位置,更新为新集合节点位置

24.调和阶段setState干了什么?

  • 代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
  • 经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
  • React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
  • 在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

25.使用 redux 有哪些原则?

  • 单一数据源:整个应用的全局 state 被存储在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
  • State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事情的普通对象。
  • 使用纯函数来执行修改:为了描述 action 如何改变 state tree,你需要编写纯的 reducers。

26.说说redux的实现原理是什么,写出核心代码?

  • 将应用的状态统一放到state中,由store来管理state
  • reducer的作用是 返回一个新的state去更新store中对用的state
  • redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中,reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新
  • subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行
  • 可以添加中间件对提交的dispatch进行重写
    核心API
  • createStore 创建仓库,接受reducer作为参数
  • bindActionCreator 绑定store.dispatchaction 的关系
  • combineReducers 合并多个reducers
  • applyMiddleware 洋葱模型的中间件,介于dispatchaction之间,重写dispatch
  • compose 整合多个中间件

27.对Redux中间件的理解?原理?常用中间件有哪些?

Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理, 其本质上一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能

实现原理:

  • applyMiddlewares的源码 中我们可以看到 ,所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getStatedispatch这两个方法

常用中间件:

  • redux-thunk:用于异步操作
  • redux-logger:用于日志记录

28.Redux 和 Vuex 有什么区别,它们有什么共同思想吗?

  • 相同点:
    • state 共享数据
    • 流程一致:定义全局state,触发,修改state
    • 原理相似,通过全局注入store。
  • 不同点:
    • 实现原理:
      • Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改
      • Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的
    • 表现层:
      • vuex定义了state、getter、mutation、action四个对象;redux定义了state、reducer、action。
      • vuex中state统一存放,方便理解;reduxstate依赖所有reducer的初始值
      • vuex有getter,目的是快捷得到state;redux没有这层,react-redux mapStateToProps参数做了这个工作。
      • vuex中mutation只是单纯赋值(很浅的一层);redux中reducer只是单纯设置新state(很浅的一层)。他俩作用类似,但书写方式不同
      • vuex中action有较为复杂的异步ajax请求;redux中action中可简单可复杂,简单就直接发送数据对象({type:xxx, your-data}),复杂需要调用异步ajax(依赖redux-thunk插件)。
      • vuex触发方式有两种commit同步和dispatch异步;redux同步和异步都使用dispatch
  • 共同思想:
    • 单一的数据源
    • 变化可以预测

29.props和state相同点和不同点?

不同点:
props是只读的,只能由父组件传递给子组件,而不能在子组件中修改。而state是可变的,在组件内部可以通过setState方法来修改其值
相同点:
1.props和state都会触发渲染更新

​ 2.props和state都是纯JS对象(用typeof来判断,结果都是object)

30.shouldComponentUpdate有什么作用?

shouldComponentUpdate () 可以理解为是否触发渲染的阀门,当状态发生改变时会走到该生命周期,shouldComponentUpdate接收两个参数props,state分别是更新前和更新后的状态,可以判断前后是否发生改变返回true和false,来决定是否往下执行

31.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历

原因:在react.js中props.children不一定是数组

  • 当前组件没有子节点 undefined
  • 有一个子节点 object
  • 多个子节点 array

react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。

32.谈谈你对immutable.js的理解?

Immutable.js采用了 持久化数据结构 ,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过 结构共享 等方式大幅提高性能

33.redux原理、工作流程及其应用,三大原则

redux: redux是专门用于集中式管理状态的javascript库,他并不是react的插件库。

redux三大核心:

  • actions
    actions英文直译过来就是行动、动作的意思,那么我们就可以猜到他表示的是“怎么做”,简单来说actions就是一个对象,actions里面有两个属性分别为type和data:
    type:标识属性,值为字符串且唯一,必要属性(你想要做什么事情
    data:数据属性,值为任意类型,可选属性(你要做事情的数据

    那我们浅浅举个栗子:比如计算器你可以进行加1减2等操作,那么加减乘除这个操作就是你的type,数字就是你的数据

  • store
    store有且只能有一个,他相当于一个最高指挥家,他负责把action动作交给对应的reducer进行执行,也就是说将state、action和reducer联系在一起的对象。

  • reducer
    reducer用于将store发过来的action完成并将结果返回给store,他接收两个参数preState(旧状态)和action(动作)并返回一个newState(新状态)。

工作流程:当组件使用store中的数据需要发生变化时,告诉action生成动作对象,通过dispatch分发对象到store,store对需要使用的reducer进行绑定,然后将action分发到对应reducer上执行相应逻辑进行数据覆盖,再将store数据渲染

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srPGmnk2-1686967105052)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685666639607.png)]

三大原则

唯一数据源(state)

数据源(state)只读

通过纯函数(pure function)改变数据源(state)

34.react-redux原理,工作流程

react-redux实现过程

react-redux执行流程详解:

初始化阶段:

  • 创建 Redux store 对象,并将 Reducer 传入 createStore 函数中。
  • 创建一个 Provider 组件,并将 Redux store 对象作为 Provider 组件的 props 传入其中。
  • 将应用根组件包装在 Provider 组件中,并渲染整个应用。

运行阶段:

  • 使用 connect 函数将组件与 Redux 中的 state 和 action creators 相连接,并将它们转化为组件的 props 属性
import { connect } from 'react-redux';
import { addToCart } from '../actions';

const Product = ({ product, addToCart }) => (
 <div>
   <h3>{product.name}</h3>
   <button onClick={() => addToCart(product)}>Add to cart</button>
 </div>
);

const mapDispatchToProps = {
 addToCart,
};

export default connect(null, mapDispatchToProps)(Product);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

更新阶段:

  • 在 Store 的 dispatch 方法中,执行 action 并更新 Store 中的 state。
  • React-Redux 根据 Store 中的新状态,检查哪些组件的 props 发生了变化。
  • 对于发生变化的组件,React-Redux 将触发相关的生命周期方法和 render 方法进行重新渲染。

工作流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OaD98GCF-1686967105053)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685667792598.png)]

35.react组件通讯的context

使用步骤:

  • 在顶层组件中创建一个 context 对象,并将需要共享的数据挂载到该对象上

    const MyContext = React.createContext(defaultValue);
    
    • 1
  • 在顶层组件的 render 方法中,使用 MyContext.Provider 组件来包裹整个应用程序,并将共享的数据传递给 value 属性

    <MyContext.Provider value={sharedData}>
        <App />
    </MyContext.Provider>
    
    • 1
    • 2
    • 3
  • 在需要使用共享数据的组件中,使用 MyContext.Consumer 组件来接收 context 的 value 属性,并在 Consumer 的子元素中使用这些数据

    <MyContext.Consumer>
        {sharedData => (
            // 此处可以使用 sharedData 来操作共享数据
        )}
    </MyContext.Consumer>
    
    • 1
    • 2
    • 3
    • 4
    • 5

36.react-redux中 Provider 组件实现原理

React-Redux 中的 Provider 组件是一个 React 组件,它使用了 React 的 Context API 来实现数据的传递。Provider 组件提供一个 context 对象,它可以让嵌套在它内部的子组件都可以访问到这个 context 对象,并且可以通过它来获取到 Redux store 中的数据。

37.react-redux中Connect原理

connect 函数是将 React 组件与 Redux Store 进行连接的重要方法。它接收两个函数作为参数,并返回一个高阶组件,通过这个高阶组件可以将 Redux Store 和 React 组件关联起来。 (实现容器组件包裹ui组件)

在原应用组件上包裹一层,使原来整个应用成为Provider的子组件,接收Redux的store作为props,通过context对象传递给子孙组件上的connect,它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。

//其中 mapStateToProps 和 mapDispatchToProps 是将 Store 和 action creator 映射到组件的 props 上的函数。
connect(mapStateToProps, mapDispatchToProps)(Product);
  • 1
  • 2

38.react-toolkit

react-toolkit是一个官方维护的包含多个有用工具的 Redux 库,旨在使 React 和 Redux 的开发变得更加简单、高效和直观

  1. 简化 Redux 工作流

redux-toolkit 提供了一种新的方式来编写 Redux 应用程序,该方式包含了常见的 Redux 模式,并通过封装样板代码来简化它们。这使得开发者可以更加专注于实现业务逻辑,而不必关心较低级别的细节。

  1. 内置常用中间件

redux-toolkit 包含了 Redux 应用程序中常用的几个中间件,如 redux-thunk 中间件、redux-saga 中间件和 redux-logger 中间件,使开发者可以轻松地使用和配置这些中间件。

  1. 强制执行不可变性

redux-toolkitcreateSlice 函数在创建 reducer 时会自动使用不可变性(immutability)来更新 state,这避免了因直接修改 state 而产生的潜在错误。

  1. 自动生成 Redux action 类型

redux-toolkit 提供了 createSlice 函数来创建 reducer,该函数还会自动为每个 action type 创建一个字符串常量,避免手动编写这些常量带来的冗余代码。

  1. 管理副作用

redux-toolkit 提供了 createAsyncThunk 函数来创建具有异步副作用的 action,该函数自动处理异步流程,并可以在状态中跟踪每个异步操作的进度和结果。

39.React.memo() 和 useMemo() 的用法是什么,有哪些区别?

React.memo 是一个高阶组件,它可以将一个纯函数组件,当组件的 props 没有变化时,会直接复用组件的渲染结果,从而避免不必要的渲染。

//当 MyComponent 的 text 属性没有变化时,MemoizedComponent 就会复用之前的渲染结果,而不会重新渲染。
function MyComponent(props) {
  return <div>{props.text}</div>;
}
const MemoizedComponent = React.memo(MyComponent);
  • 1
  • 2
  • 3
  • 4
  • 5

useMemo 是一个 Hook,它可以用于缓存计算结果,以避免重复计算。当传入的依赖项没有变化时,会直接返回缓存的结果。

//如果 calculate 方法比较耗时,为了避免不必要的计算,我们可以使用 useMemo 来缓存计算结果:
function MyComponent({ a, b }) {
  const result = useMemo(() => calculate(a, b), [a, b]);
  return <div>{result}</div>;
}
  • 1
  • 2
  • 3
  • 4
  • 5

区别:

React.memouseMemo 都可以用于优化 React 应用的性能,但是它们的优化对象和优化手段不同。React.memo 通过避免组件的不必要渲染来提高性能,而 useMemo 通过避免重复计算来提高性能。在实际开发中,需要根据具体场景和需求来选择适合的优化方法。

40.usecallback,usememo区别

useCallback 用于缓存函数,以避免不必要的函数创建和渲染。当依赖项发生变化时,会返回一个新的函数引用,否则直接返回之前缓存的函数引用。

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);
  • 1
  • 2
  • 3

useMemo 用于缓存计算结果,以避免重复计算和渲染。当依赖项发生变化时,会重新计算并返回新的计算结果

const memoizedValue = useMemo(() => {
  return heavyComputation(a, b);
}, [a, b]);
  • 1
  • 2
  • 3

useCallback 通过避免函数创建和渲染来提高性能,而 useMemo 通过避免重复计算和渲染来提高性能

41.react使用ref

ref 是用来访问 DOM 元素或组件实例的引用的一种方式。

字符串回调

class MyComponent extends React.Component {
  componentDidMount() {
    console.log(this.refs.myInput);
    // 输出:<input type="text" />
  }
  render() {
    return <input type="text" ref="myInput" />;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

函数回调

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = null;
  }
  componentDidMount() {
    console.log(this.myRef);
    // 输出:<input type="text" />
  }
  render() {
    return <input type="text" ref={node => this.myRef = node} />;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

React.createRef

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  componentDidMount() {
    console.log(this.myRef.current);
    // 输出:<input type="text" />
  }
  render() {
    return <input type="text" ref={this.myRef} />;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

42.为什么循环和判断不能使用hooks

原因:

​ 循环、条件语句等块级作用域会影响 Hooks 调用的次数和顺序,从而破坏 React 内部的依赖关系和渲染逻辑,导致组件出现无法预期的错误。因此,为了保证组件能够正常渲染和更新,我们需要遵循 React Hooks 的使用规范,在顶层作用域中调用 Hooks。

43.React实现过度动画

使用第三方库: React Transition Group 详细学习过度动画

注意: CSSTransition 中类命名方式classNames

44. react懒加载实现原理

React 的懒加载实现原理主要是基于 ES6 的 import() 函数和 React 的 lazy 函数。

import React, { lazy, Suspense } from "react";

const LazyComponent = lazy(() => import("./LazyComponent"));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

当我们使用 lazy 函数时,React 会在运行时动态创建一个新的组件,这个新的组件继承了原始组件的所有属性和方法,并且它的 render 方法被重写成一个异步函数。当这个新的组件需要被渲染时,React 就会自动触发它的 render 方法,这个方法会异步加载原始组件的代码,并将其渲染到页面上。

这里涉及到了 ES6 中的 import() 函数,它是一个异步函数,用来动态加载 JavaScript 模块。import() 函数会返回一个 Promise 对象,当模块加载完成后,Promise 对象就会被 resolve,我们可以通过 then 方法获取模块的默认导出对象。

45.immutable

Immutable 是一个 JavaScript 库,它提供了一些数据结构和 API,使得创建不可变数据成为可能。React 中使用 Immutable 可以带来以下好处:

  • 性能优化: React 中使用的 Virtual DOM 技术会频繁地进行比较和更新操作,而不可变数据可以减少需要更新的节点数量,从而提高应用的性能和响应速度。
  • 便于管理状态: React 应用中的状态通常非常复杂,使用不可变数据可以更加方便地管理状态,并且避免了因为状态被修改而引发的副作用。
  • 并发安全: 在高并发环境下,使用不可变数据可以减少数据竞争和锁竞争,提高并发安全性能。

immutable创建不可变数据类型,想要修改只能通过数据覆盖创建新的变量,对react进行性能优化

46.useState为什么返回数组而不是对象

原因:React 团队认为,使用数组可以带来更好的灵活性和易用性

优点:

  • 无需命名: 当使用数组时,我们可以使用数组解构语法来命名状态变量和修改函数,并且不需要考虑命名冲突等问题。
  • 直接修改: 使用数组解构后,我们可以直接对数组元素进行修改操作,而无需再次调用对象中的某个方法或属性。
  • 易于扩展: 在未来的版本中,React 还可能会增加更多的状态相关的 Hook,使用数组可以使得新增的 Hook 更加容易添加到现有的语法中

47.类组件为什么不能使用hooks

Hooks 是基于函数式编程思想设计的,不支持类组件的一些特性。但是,React 提供了一些方法,可以让开发者在类组件中使用 Hooks 的部分功能,或者将类组件转换为函数组件来使用 Hooks。

48.redux-thunk和redux-saga区别

redux-thunk 的设计思路是将异步逻辑封装到“thunk”函数中,这个函数接收 dispatch 方法作为参数,并返回一个带有回调函数的函数。这个回调函数在异步操作完成后被调用,然后再通过 dispatch 方法触发一个 action,更新 Redux store 中的数据。redux-thunk 适合用于处理简单的异步逻辑,比如发送 AJAX 请求或者获取本地存储数据等。 没有拓展api

redux-saga 则采用了另外一种设计思路,它使用了 ES6 的 generator 函数来实现异步逻辑的管理。在 redux-saga 中,使用 generator 函数定义一个 saga,它可以监听一个或多个 action,并在相应的 action 被触发后执行一些副作用,比如发送 AJAX 请求、触发其他 action 等。redux-saga 还提供了一些辅助函数和特性(api),比如 takeLatestputcall 等,使得开发者可以更加方便地管理异步流程,处理错误和取消请求等。

49.react合成事件使用原因,原理

探索合成事件

React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象

使用原因:

  • 进行浏览器兼容,实现更好的跨平台

    ​ React 采用的是顶层事件代理机制,能够保证冒泡一致性,可以跨浏览器执行。React 提供的合成事件用来抹平不同浏览器事件对象之间的差异,将不同平台事件模拟合成事件。

  • 避免垃圾回收

    ​ 事件对象可能会被频繁创建和回收,因此 React 引入事件池,在事件池中获取或释放事件对象。即 React 事件对象不会被释放掉,而是存放进一个数组中,当事件触发,就从这个数组中弹出,避免频繁地去创建和销毁(垃圾回收)。

  • 方便事件统一管理和事务机制

原理:

  • 事件绑定
    • 在React17之前,React是把事件委托在document上的,React17及以后版本不再把事件委托在document上,而是委托在挂载的容器上
    • 原生事件和合成事件两者其实是通过一个叫事件插件(EventPlugin)的模块产生关联的,每个插件只处理对应的合成事件,比如onClick事件对应SimpleEventPlugin插件,这样React在一开始会把这些插件加载进来,通过插件初始化一些全局对象,比如其中有一个对象是registrationNameDependencies,它定义了合成事件与原生事件的对应关系
  • 事件触发
    • 事件触发都会执行dispatchEvent函数,当触发事件时会对当前元素的所有父元素处理构造成合成对象,将合成事件一次存放入eventQueue中,遍历 eventQueue 模拟一遍捕获和冒泡阶段,然后通过runEventsInBatch方法依次触发调用每一项的监听事件

50.React事件代理机制

React 并不会把所有的处理函数直接绑定在真实的节点上。而是把所有的事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。

  • 所有事件都是委托在id = root的DOM元素中(网上很多说是在document中,17版本不是了);
  • 在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发;
  • React自身实现了一套事件冒泡捕获机制;
  • React实现了合成事件SyntheticEvent
  • React17版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16版本及之前);
  • 事件一旦在id = root的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;

51.React事件和原生事件的执行顺序

import React, { useRef, useEffect } from "react";
import "./styles.css";

const logFunc = (target, isSynthesizer, isCapture = false) => {
    const info = `${isSynthesizer ? "合成" : "原生"}事件,${
        isCapture ? "捕获" : "冒泡"}阶段,${target}元素执行了`;
    
    console.log(info);
};

const batchManageEvent = (targets, funcs, isRemove = false) => {
    targets.forEach((target, targetIndex) => {
        funcs[targetIndex].forEach((func, funcIndex) => {
            target[isRemove ? "removeEventListener" : "addEventListener"](
                "click",
                func,
                !funcIndex
            );
        });
    });
};

export default function App() {
    const divDom = useRef();
    const h1Dom = useRef();
    useEffect(() => {
    
        const docClickCapFunc = () => logFunc("document", false, true);
        const divClickCapFunc = () => logFunc("div", false, true);
        const h1ClickCapFunc = () => logFunc("h1", false, true);
        const docClickFunc = () => logFunc("document", false);
        const divClickFunc = () => logFunc("div", false);
        const h1ClickFunc = () => logFunc("h1", false);

        batchManageEvent(
            [document, divDom.current, h1Dom.current],
            [
                [docClickCapFunc, docClickFunc],
                [divClickCapFunc, divClickFunc],
                [h1ClickCapFunc, h1ClickFunc]
            ]
        );

        return () => {
            batchManageEvent(
                   [document, divDom.current, h1Dom.current],
                [
                    [docClickCapFunc, docClickFunc],
                    [divClickCapFunc, divClickFunc],
                    [h1ClickCapFunc, h1ClickFunc]
                ],
                true
            );
        };
    }, []);

    return (
        <div
          ref={divDom}
          className="App1"
          onClickCapture={() => logFunc("div", true, true)}
          onClick={() => logFunc("div", true)}
        >
          <h1
            ref={h1Dom}
            onClickCapture={() => logFunc("h1", true, true)}
            onClick={() => logFunc("h1", true)}
          >
            Hello CodeSandbox
          </h1>
        </div>
    );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

React16

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0te4nKyx-1686967105054)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685930695759.png)]

React17

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-39vZwaap-1686967105055)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685930673755.png)]

总结

  • 16版本先执行原生事件,当冒泡到document时,统一执行合成事件,
  • 17版本在原生事件执行前先执行合成事件捕获阶段,原生事件执行完毕执行冒泡阶段的合成事件,通过根节点来管理所有的事件

52.jsx转换真实dom流程

  • 使用React.createElement()或JSX编写React组件,实际上所有的JSX都会转换成React.createElement(),Babel完成转换过程
  • createElement函数对key和ref等特殊的props进行处理,生成vDom
  • ReactDOM.render将生成好的dom渲染到容器上,进行处理转化成真实dom

53.什么是JSX?

JSX即JavaScript XML。一种在React组件内部构建标签的类XML语法。JSX为react.js开发的一套语法糖,也是react.js的使用基础。React在不使用JSX的情况下一样可以工作,然而使用JSX可以提高组件的可读性,因此推荐使用JSX。

优点:

  • 允许使用熟悉的语法来定义 HTML 元素树;
  • 提供更加语义化且移动的标签;
  • 程序结构更容易被直观化;
  • 抽象了 React Element 的创建过程;
  • 可以随时掌控 HTML 标签以及生成这些标签的代码;
  • 是原生的 JavaScript。

八、微信小程序篇

1. 请谈谈WXML与标准的html的异同?

(1) WXML是小程序框架设计的一套标签语言,用来构建小程序页面的结构,其作用类似于网页开发中的html

① 都是用来描述页面的结构

② 都由标签,属性等构成

③ 标签名字不一样,且小程序标签更少,单一标签更多

④ 小程序多了一些wx:if这样的属性以及{{}}这样的表达式

⑤ WXML仅能在微信小程序开发者工具中预览,而HTML可以在浏览器内预览

⑥ 组件封装不同,WXML对组件进行了重新封装

⑦ 小程序运行在JS Core内,没有DOM树和window对象,小程序中无法使用window对象和document对象

2. 请谈谈WXSS和CSS的异同?

(1) 新增了rpx尺寸单位,css中需要手动进行像素单位换算,例如rem

(2) WXSS支持新的尺寸rpx,在不同大小的屏幕上小程序会自动进行换算

(3) 提供了全局样式和局部样式,项目根目录中的app.wxss会作用于所有小程序页面,局部页面的.wxss样式仅对当前页面生效

(4) WXSS仅支持部分css选择器:

① 类选择器,id选择器

② 元素选择器

③ 并集选择器,后代选择器

④ ::after和::before等伪类选择器

3.请谈谈微信小程序主要目录和文件的作用

(1) project.config.json: 项目配置文件,用得最多的就是配置是否开启https校验;

(2) App.js :设置一些全局的基础数据等,页面的脚本文件,存放页面的数据、事件处理函数等;

(3) App.json :当前页面的配置文件,配置窗口的外观 、表现等,页面中的配置项会覆盖 app.json的;

(4) App.wxss :公共样式,引入iconfont等;

(5) pages: 里面包含一个个具体的页面;

(6) index.json: (配置当前页面标题和引入组件等);

(7) index.wxml:页面的模板结构文件;

(8) .wxss文件:当前页面的样式表文件;

(9) index.js :(页面的逻辑,请求和数据处理等)

4.请谈谈小程序的双向绑定和vue的异同

(1) 小程序双向绑定:首先通过 bindinput 绑定文本框的输入事件

① 在 data 中声明一个变量 content ,将其动态绑定成文本框的 value 值

② 在 bindinput 事件中通过事件参数 e.detail.value 可以获取到文本框中最新的 value 值

③ 通过 this.setData 将文本框最新的 value 值 赋值给 动态绑定的value值 content 即可实现数据的双向绑定

(2) Vue双向绑定:首先为文本框绑定 @input 监听文本框的输入事件

① 为文本框动态绑定 value 属性,其值是在data中定义的变量

② 在 @input绑定的事件中 通过事件参数 event.target.value 可以获取到 input 框中最新的value值

③ 将其重新获取到的 value 赋值给 value值动态绑定的那个变量

(3) 大体上区别不大,绑定事件不同,以及获取value值的具体方式不同,以及在小程序中设置data中的数据,
需要调用 this.setData方法进行设置

5.简单描述下微信小程序的相关文件类型

(1) WXML(weixin Markup Language) 是框架设计的一套标签语言,结合基础组件,事件系统,可以构建出页面的结构。内容主要事微信自己定义的一套组件。

(2) WXSS(WeiXin Style Sheets) 是一套样式语言,主要用于描述 WXML 的组件样式。

(3) JS 逻辑处理,网络请求

(4) json 小程序设置,静态配置

(5) app.json 必须要有这个文件,此文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置tabBar 最少两个

6.微信小程序有哪些传值(传递数据)方法

(1) 使用全局变量传递数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pu3nDBnO-1686967105056)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps1.jpg)]

(2) 使用本地存储数据传递

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H6cLbqBk-1686967105057)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps2.jpg)]

(3) 使用路由传递数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4zSUW0R-1686967105058)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps3.jpg)]

7.Bindtap和catchtap区别?

(1) Bindtap和catchtap都属于点击事件函数,将事件绑定到组件上,点击组件后可以触发函数

bindtap :子元素使用bindtap绑定事件后,执行的时候,会冒泡到父元素(触发父元素上绑定的bingtap事件)

catchtap :不会冒泡到父元素上,阻止事件冒泡

8.wx.navigateTo(),wx.redirectTo(),wx.switchTab(),wx.navigateBack(),wx.reLaunch()的区别?

(1) wx.navigateTo(Object):保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层

(2) Wx.navigateBack():关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层

(3) wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面

(4) wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面

(5) wx.reLaunch():关闭所有页面,打开到应用内的某个页面

9.微信小程序和h5区别?

(1) 从开发的角度:H5和小程序的开发工具就非常不同,小程序都是依赖于微信客户端的,所以相对来说开发工具没有H5那么多;与标准的H5语言是不一样的;而且还独立了很多的原生app的组件,所以它在组件封装上与H5也都是有所不同

(2) 从运行环境:网页开发者需要面对的环境是各式各样的浏览器,PC 端需要面对 IE、Chrome、QQ浏览器等,在移动端需要面对Safari、Chrome以及 iOS、Android 系统中的各式 WebView 。而小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的微信客户端,以及用于辅助开发的小程序开发者工具,小程序中三大运行环境也是有所区别的。

(3) 服务器配置:因为小程序的性能会比H5 高一些,所以服务器的配置要求上来说,小程序的要求要比H5更高一些系统权限:因为微信能获取到更多的系统权限,如网络通信状态、数据缓存能力等,这些系统级权限都能与微信小程序无缝衔接,这也就是官方宣称的微信小程序能够拥有Native App(原生APP)的流畅性能。而H5 web应用对系统本身的权限的获取则相对少了很多,这一点恰巧是H5 web应用经常被诟病的地方。也因此,H5的大多数应用被圈定在业务逻辑简单、功能单一的范围上。

(4) 标签名字:写 HTML 的时候,经常会用到的标签是 div, p, span,小程序的 WXML 用的标签是 view, button, text 等等,这些标签就是小程序给开发者包装好的基本能力。小程序多了一些 wx:if 这样的属性以及 {{ }} 这样的表达式在网页的一般开发流程中,我们通常会通过 JS 操作 DOM (对应 HTML 的描述产生的树),以引起界面的一些变化响应用户的行为。

10.小程序和vue写法区别?

(1) 事件定义区别:vue通过@绑定事件,小程序通过bind

(2) 事件函数传值:vue传值直接写在函数括号中,微信小程序传值需要用data-自定义名字={{需要传递的值}}

(3) 关键字引用:vue中属性名前面加 “:” 或者 v-bind,微信小程序中只需要属性值加“{{}}”包起来就行

(4) 指令使用方式:vue中通过v-使用,小程序中通过wx:使用

11.Rpx的理解:

(1) Rpx是微信小程序中响应单位

(2) rpx是微信小程序独有的、解决屏幕自适应的尺寸单位

(3) 可以根据屏幕宽度进行自适应,不论大小屏幕,规定屏幕宽为750rpx,再页面宽度750px时,1rpx = 1px

12.微信小程序可以做dom操作吗?

(1) 微信小程序不支持document.querySelect获取元素,因为微信小程序的渲染层和逻辑层是独立的,但是它内置了获取元素的两种方法

① wx.createSelectorQuery()获取dom元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEW3uzli-1686967105059)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps4.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XH7ohB3C-1686967105059)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps5.jpg)]

13.小程序和vue区别?

(1) 生命周期不一样,微信小程序生命周期比较简单

(2) 数据绑定也不同,微信小程序数据绑定需要使用{{}},vue 直接:就可以

(3) 显示与隐藏元素,vue中,使用 v-if 和 v-show 控制元素的显示和隐藏,小程序中,使用wx-if 和hidden 控制元素的显示和隐藏

(4) 事件处理不同,小程序中,全用 bindtap(bind+event),或者 catchtap(catch+event) 绑定事件,vue:使用 v-on:event 绑定事件,或者使用@event 绑定事件

(5) 数据双向绑定也不也不一样在 vue中,只需要再表单元素上加上 v-model,然后再绑定 data中对应的一个值,当表单元素内容发生变化时,data中对应的值也会相应改变,这是 vue非常 nice 的一点。微信小程序必须获取到表单元素,改变的值,然后再把值赋给一个 data中声明的变量。

14.小程序自定义tabbar理解?

(1) 首先在挨批评。App.json中配置tabbar,开启custom 自定义tabbar,配置完之后创建custom-tab-bar文件,这时候会在小程序底部生成文件内容,给index.wxml添加tabBar的结构代码, 给index.js 添加数据配置 和 事件方法

15.微信小程序如何设置缓存?

(1) wx.getStorage/wx.getStorageSync 读取本地缓存,通过wx.setStorage/wx.setStorageSync 写数据到缓存,其中Sync后缀的接口表示是同步接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOmNe545-1686967105060)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps6.jpg)]

16. 微信小程序如何进行网络请求?

(1) wx.request(Object object) 用于发送网络请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5VZUL7r-1686967105062)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps7.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-so2LhJfi-1686967105063)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps8.jpg)]

17. 小程序生命周期分为三个部分

(1) 应用级:

① onLaunch:小程序初始化完成时触发,全局只触发一次

② onShow:小程序启动或切前台显示时触发

③ onHide:小程序从前台进入后台时触发(如 切换到其他的App

④ onError:小程序发生脚本错误或 API 调用报错时触发

(2) 页面级:

① onLoad:页面加载时执行,只执行一次

② onShow:页面展示时执行,执行多次

③ onReady:页面初次渲染时执行,只执行一次

④ onHide:页面从前台进入后台时执行

⑤ onUnload:页面卸载时执行

(3) 组件级:

created(重要):组件实例刚刚被创建好时触发

attached(重要):在组件完全初始化完毕、进入页面节点树后被触发

③ ready:在组件在视图层布局完成后执行

④ moved:在组件实例被移动到节点树另一个位置时执行

detached(重要):在组件离开页面节点树后被触发

⑥ Error:每当组件方法抛出错误时执行

18. 微信小程序如何做模块化?

(1) 可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口

(2) 需要使用这些模块的文件中,使用 require 将公共代码引入

19. 微信所有api都放在哪里,简单介绍几个

(1) 小程序全局对象是: wx,所有的 API 都保存在 wx 对象中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzoRS18A-1686967105064)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps9.jpg)]

20. 微信小程序应用和页面生命周期触发顺序?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZlYZbvim-1686967105064)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps10.jpg)]

21. 微信小程序自定义组件使用

(1) 创建components文件夹

(2) 创建组件文件(例tabs),新建为component形式

(3) 在tabs的json文件中设置component:true

(4) 在需要引入的组件页面的json文件中,在usingComponent里面写键值对,组件名:路径

(5) 在需要页面写入标签

注意:WXML 节点标签名只能是小写字母、中划线和下划线的组合

22. 微信小程序事件通道使用

微信小程序事件通道(事件总线)是用于在小程序多个页面或组件之间通过触发事件进行通信的机制。通过wx.navigateTo或wx.redirectTo方法跳转到目标页面或组件时,传入events参数,并将它赋值为事件通道对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z9pQwqTy-1686967105065)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps11.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6a1HlQJq-1686967105066)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps12.jpg)]

23. 小程序如何使用vant组件库

如果是以js为web页面脚本语言创建的小程序,本身不存在package.json文件,就不可以使用npm命令

先通过npm init初始化npm,产生package.json文件

通过vantweapp官网 npm下载组件库

在微信小程序中通过工具构建npm

移除app.json中“style”:“v2”,避免小程序样式高于vant导致样式混乱

在app.json中usingComponents注册组件

24. 微信小程序父子传递

父传子:通过父组件标签绑定属性,子组件在properties中接收属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olTg2Lfx-1686967105067)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps13.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NMW1E5Xq-1686967105068)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps14.jpg)]

子传父:通过父组件bind自定义事件,绑定自身函数,子组件在触发函数中通过this.triggerEvent(‘父组件bind事件名’,传递参数)传递给父组件绑定函数中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oNSSzdfi-1686967105068)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps15.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JOYkl8El-1686967105069)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps16.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s8Gidbyv-1686967105070)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps17.jpg)]

25. 小程序授权登录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7YYIVIy-1686967105071)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps18.jpg)]

26. web-view

web-view 是一个 web 浏览器组件,可以用来承载网页的容器,会自动铺满整个页面.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vj1a9jN1-1686967105072)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps19.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mQueHEZG-1686967105073)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps20.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MvzbHfJ-1686967105074)(file:///C:\Users\lenovo\AppData\Local\Temp\ksohtml14876\wps21.jpg)]

六、Webpack 篇

1.webpack五大核心

  1. Entry - 入口

Entry 指示 Webpack 从哪个模块开始构建内部依赖图,以及如何将所有依赖项连接在一起。

  1. Output - 输出

Output 定义了 Webpack 构建的输出文件的位置和文件名。

  1. Loader - 加载器

Loader 用于对模块的源代码进行转换,以便于 Webpack 处理。例如,当 Webpack 遇到一个 “.css” 文件时,使用 “css-loader” 和 “style-loader” 将其转换为 JavaScript 代码以便于在浏览器中呈现样式。

  1. Plugin - 插件

Plugin 在 Webpack 的构建过程中扮演一个关键的角色,它可以完成各种各样的任务,例如压缩代码、拷贝文件到输出目录、创建全局变量等等。

  1. Mode - 模式

Mode 是 Webpack 4 引入的一个新特性,它提供了三种不同的构建模式,即 “development”、“production” 和 “none”,分别对应着开发模式、生产模式和不设置模式。

1. 谈谈你对Webpack的理解(Webpack是什么?)

Webpack 是一个 静态模块打包器,可以分析各个模块的依赖关系,项目中的所有资源皆为模块,通过分析模块间的依赖关系,在其内部递归构建出一个依赖关系图,其中包含应用程序需要的每个模块,然后将这些模块打包成一个或多个 bundle。最终编绎输出模块为 HTML、JavaScript、CSS 以及各种静态文件(图片、字体等)。

webpack 就像一条生产线,要经过一系列处理流程(loader)后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。 webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。

webpack的主要作用如下:
  • 模块打包 可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。
  • 编译兼容 在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过webpack的Loader机制,不仅仅可以帮助我们对代码做polyfill,还可以编译转换诸如.less,.vue,.jsx这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。
  • 能力扩展 通过webpack的Plugin机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。

2. Webpack的打包过程/打包原理/构建流程?

  1. 初始化:启动构建,读取与合并配置参数,加载plugin,实例化Compiler
  2. 编译:从Entry出发,针对每个Module串行调用对应的Loader去翻译文件中的内容,再找到该Module依赖的Module,递归的进行编译处理
  3. 输出:将编译后的Module组合成Chunk,将Chunk转换成文件,输出到文件系统中

细节:

Webpack CLI 通过 yargs模块解析 CLI 参数,并转化为配置对象option(单入口:Object,多入口:Array),调用 webpack(option) 创建 compiler 对象。

如果有 option.plugin,则遍历调用plugin.apply()来注册 plugin,

判断是否开启了 watch,如果开启则调用 compiler.watch,否则调用 compiler.run,开始构建。

创建 Compilation 对象来收集全部资源和信息,然后触发 make 钩子。

make阶段从入口开始递归所有依赖,

每次遍历时调用对应Loader翻译文件中内容,然后生成AST,遍历AST找到下个依赖继续递归,

根据入口和模块之间关系组装chunk,输出到dist中的一个文件内。

在以上过程中,webpack会在特定的时间点(使用tapable模块)广播特定的事件,插件监听事件并执行相应的逻辑,并且插件可以调用webpack提供的api改变webpack的运行结果

3. loader的作用

webpack中的loader是一个函数,主要为了实现源码的转换,所以loader函数会以源码作为参数,比如,将ES6转换为ES5,将less转换为css,然后再将css转换为js,以便能嵌入到html文件中

默认情况下,webpack只支持对js和json文件进行打包,但是像css、html、png等其他类型的文件,webpack则无能为力。因此,就需要配置相应的loader进行文件内容的解析转换。

4. 有哪些常见的Loader?他们是解决什么问题的?

常用的loader如下:

  • image-loader:加载并且压缩图片文件。
  • less-loader:加载并编译 LESS 文件。
  • sass-loader:加载并编译 SASS/SCSS 文件。
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性,使用css-loader必须要配合使用style-loader。
  • style-loader:用于将 CSS 编译完成的样式,挂载到页面的 style 标签上。需要注意 loader 执行顺序,style-loader 要放在第一位,loader 都是从后往前执行。
  • babel-loader:把 ES6 转换成 ES5
  • postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码。
  • vue-loader:加载并编译 Vue 组件。
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
  • url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)。
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试。

5. plugin的作用

plugin是一个类,类中有一个apply()方法,主要用于Plugin的安装,可以在其中监听一些来自编译器发出的事件,在合适的时机做一些事情。

webpack中的plugin赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在webpack的不同阶段(钩子 / 生命周期),贯穿了webpack整个编译周期。目的在于「解决 loader 无法实现的其他事」。

6. 有哪些常见的Plugin?他们是解决什么问题的?

  • html-webpack-plugin:可以复制一个有结构的html文件,并自动引入打包输出的所有资源(JS/CSS)
  • clean-webpack-plugin:重新打包自动清空 dist 目录
  • mini-css-extract-plugin:提取 js 中的 css 成单独文件
  • optimize-css-assets-webpack-plugin:压缩css
  • uglifyjs-webpack-plugin:压缩js
  • commons-chunk-plugin:提取公共代码
  • define-plugin:定义环境变量

7. Webpack中Loader和Plugin的区别

运行时机
1.loader运行在编译阶段
2.plugins 在整个周期都起作用

使用方式
Loader:1.下载 2.使用
Plugin:1.下载 2.引用 3.使用

loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中;plugin赋予了webpack各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader无法实现的其他事。

在运行时机上,loader 运行在打包文件之前;plugin则是在整个编译周期都起作用。

在配置上,loader在module.rules中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性;plugin在 plugins中单独配置,类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入。

8. webpack的热更新是如何做到的?说明其原理?

热更新的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上webpack-dev-server与浏览器之间维护了一个websocket,当本地资源发生变化时,webpack-dev-server会向浏览器推送更新,并带上构建时的hash,让客户端与上一次资源进行对比。客户端对比出差异后会向webpack-dev-server发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向webpack-dev-server发起 jsonp 请求获取该chunk的增量更新。

后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader和vue-loader都是借助这些 API 实现热更新。

详细:
1、在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
2、webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,并且告诉 webpack,将代码打包到内存中。
3、webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念
4、webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,
同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又交回给了 webpack,webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏览器,也就没有后面那些步骤了。HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。
5、决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码。

9. 如何解决循环依赖问题

Webpack 中将 require 替换为 *webpack_require*,会根据 moduleId 到 installedModules 找是否加载过,加载过则直接返回之前的 export,不会重复加载。

10. 如何提高Webpack构建速度

1. 代码压缩
  • JS 压缩
    webpack 4.0默认在生产环境的时候是支持代码压缩的,即mode=production模式下。实际上webpack 4.0默认是使用terser-webpack-plugin这个压缩插件,在此之前是使用 uglifyjs-webpack-plugin,两者的区别是后者对 ES6 的压缩不是很好,同时我们可以开启 parallel参数,使用多进程压缩,加快压缩。
  • CSS 压缩
    CSS 压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等。可以使用另外一个插件:css-minimizer-webpack-plugin。
  • HTML 压缩
    使用HtmlWebpackPlugin插件来生成 HTML 的模板时候,通过配置属性minify进行 html 优化。
module.exports = {
plugin:[
  new HtmlwebpackPlugin({
    minify:{
      minifyCSS: false, // 是否压缩css
      collapseWhitespace: false, // 是否折叠空格
      removeComments: true // 是否移除注释
    }
  })
  ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
2. 图片压缩

配置image-webpack-loader

3. Tree Shaking

Tree Shaking是一个术语,在计算机中表示消除死代码,依赖于 ES Module 的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)。在webpack实现Tree shaking有两种方案:

usedExports:通过标记某些函数是否被使用,之后通过 Terser 来进行优化的

module.exports = {
    ...
    optimization:{
        usedExports
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用之后,没被用上的代码在webpack打包中会加入unused harmony export mul注释,用来告知Terser在优化时,可以删除掉这段代码。

sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用

sideEffects用于告知webpack compiler哪些模块时有副作用,配置方法是在package.json中设置sideEffects属性。如果sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports。如果有些文件需要保留,可以设置为数组的形式,如:

"sideEffecis":[
    "./src/util/format.js",
    "*.css" // 所有的css文件
]
  • 1
  • 2
  • 3
  • 4
4. 缩小打包域

排除webpack不需要解析的模块,即在使用loader的时候,在尽量少的模块中去使用。可以借助 include和exclude这两个参数,规定loader只在那些模块应用和在哪些模块不应用。

5. 减少 ES6 转为 ES5 的冗余代码

使用、bable-plugin-transform-runtime插件

6. 提取公共代码

通过配置CommonsChunkPlugin插件,将多个页面的公共代码抽离成单独的文件

7. 其他

组件懒加载、路由懒加载、开启gzip、公共的第三方包上cdn、配置cache缓存Loader对文件的编译副本、配置resolve提高文件的搜索速度(@: src)


七、性能优化篇

1. 浏览器缓存优化

为了让浏览器缓存发挥最大作用,该策略尽量遵循以下五点就能发挥浏览器缓存最大作用。

  • 「考虑拒绝一切缓存策略」Cache-Control:no-store
  • 「考虑资源是否每次向服务器请求」Cache-Control:no-cache
  • 「考虑资源是否被代理服务器缓存」Cache-Control:public/private
  • 「考虑资源过期时间」Expires:t/Cache-Control:max-age=t,s-maxage=t
  • 「考虑协商缓存」Last-Modified/Etag

缓存策略通过设置HTTP报文实现,在形式上分为**「强缓存/强制缓存」「协商缓存/对比缓存」**。为了方便对比,笔者将某些细节使用图例展示,相信你有更好的理解。
在这里插入图片描述
在这里插入图片描述
整个缓存策略机制很明了,先走强缓存,若命中失败才走协商缓存。若命中强缓存,直接使用强缓存;若未命中强缓存,发送请求到服务器检查是否命中协商缓存;若命中协商缓存,服务器返回304通知浏览器使用本地缓存,否则返回最新资源

有两种较常用的应用场景值得使用缓存策略一试,当然更多应用场景都可根据项目需求制定。

  • 「频繁变动资源」:设置Cache-Control:no-cache,使浏览器每次都发送请求到服务器,配合Last-Modified/ETag验证资源是否有效
  • 「不常变化资源」:设置Cache-Control:max-age=31536000,对文件名哈希处理,当代码修改后生成新的文件名,当HTML文件引入文件名发生改变才会下载最新文件

2. 渲染层面性能优化

**「渲染层面」**的性能优化,无疑是如何让代码解析更好执行更快。因此笔者从以下五方面做出建议。

  • 「CSS策略」:基于CSS规则
  • 「DOM策略」:基于DOM操作
  • 「阻塞策略」:基于脚本加载
  • 「回流重绘策略」:基于回流重绘
  • 「异步更新策略」:基于异步更新

上述五方面都是编写代码时完成,充满在整个项目流程的开发阶段里。因此在开发阶段需时刻注意以下涉及到的每一点,养成良好的开发习惯,性能优化也自然而然被使用上了。

渲染层面性能优化更多表现在编码细节上,而并非实体代码。简单来说就是遵循某些编码规则,才能将渲染层面性能优化发挥到最大作用。

**「回流重绘策略」**在渲染层面性能优化里占比较重,也是最常规的性能优化之一。上年笔者发布的掘金小册《玩转CSS的艺术之美》使用一整章讲解回流重绘,本章已开通试读,更多细节请戳这里。

CSS策略
  • 避免出现超过三层的嵌套规则
  • 避免为ID选择器添加多余选择器
  • 避免使用标签选择器代替类选择器
  • 避免使用通配选择器,只对目标节点声明规则
  • 避免重复匹配重复定义,关注可继承属性
DOM策略
  • 缓存DOM计算属性
  • 避免过多DOM操作
  • 使用DOMFragment缓存批量化DOM操作
阻塞策略
  • 脚本与DOM/其它脚本的依赖关系很强:对``设置defer
  • 脚本与DOM/其它脚本的依赖关系不强:对``设置async
回流重绘策略
  • 缓存DOM计算属性
  • 使用类合并样式,避免逐条改变样式
  • 使用display控制DOM显隐,将DOM离线化
异步更新策略
  • 异步任务中修改DOM时把其包装成微任务

3. 性能优化六大指标

六大指标基本囊括大部分性能优化细节,可作为九大策略的补充。笔者根据每条性能优化建议的特征将指标划分为以下六方面。

  • 「加载优化」:资源在加载时可做的性能优化
  • 「执行优化」:资源在执行时可做的性能优化
  • 「渲染优化」:资源在渲染时可做的性能优化
  • 「样式优化」:样式在编码时可做的性能优化
  • 「脚本优化」:脚本在编码时可做的性能优化
  • 「V8引擎优化」:针对V8引擎特征可做的性能优化

八、其他杂项篇

1. 常见的浏览器内核有哪些?

  • 主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
    • 渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
    • JS引擎则:解析和执行javascript来实现网页的动态效果。
  • 最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
  • 常见内核
    • Trident 内核:IE, MaxThon, TT, The World, 360, 搜狗浏览器等。[又称 MSHTML]
    • Gecko 内核:Netscape6 及以上版本,FF, MozillaSuite / SeaMonkey 等
    • Presto 内核:Opera7 及以上。 [Opera内核原为:Presto,现为:Blink;]
    • Webkit 内核:Safari, Chrome等。 [ Chrome的:Blink(WebKit 的分支)]

2. 网页前端性能优化的方式有哪些?

1.压缩 css, js, 图片
2.减少 http 请求次数, 合并 css、js 、合并图片(雪碧图)
3.使用 CDN
4.减少 dom 元素数量
5.图片懒加载
6.静态资源另外用无 cookie 的域名
7.减少 dom 的访问(缓存 dom)
8.巧用事件委托
9.样式表置顶、脚本置低

3. 网页从输入网址到渲染完成经历了哪些过程?

大致可以分为如下7步:

  • 输入网址;
  • 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
  • 与web服务器建立TCP连接;
  • 浏览器向web服务器发送http请求;
  • web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
  • 浏览器下载web服务器返回的数据及解析html源文件;
  • 生成DOM树,解析css和js,渲染页面,直至显示完成;

4. 线程与进程的区别?

  • 一个程序至少有一个进程,一个进程至少有一个线程.
  • 线程的划分尺度小于进程,使得多线程程序的并发性高。
  • 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  • 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

5. HTTP常见的状态码?

100 Continue 继续,一般在发送post请求时,已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Found 临时性重定向。
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
304 Not Modified 自从上次请求后,请求的网页未修改过。
400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
401 Unauthorized 请求未授权。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。
500 Internal Server Error 最常见的服务器端错误。
503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。

6. 图片懒加载?

当页面滚动的时间被触发 -> 执行加载图片操作 -> 判断图片是否在可视区域内 -> 在,则动态将data-src的值赋予该图片

7. 移动端性能优化?

  • 尽量使用css3动画,开启硬件加速
  • 适当使用touch时间代替click时间
  • 避免使用css3渐变阴影效果
  • 可以用transform: translateZ(0) 来开启硬件加速
  • 不滥用float。float在渲染时计算量比较大,尽量减少使用
  • 不滥用web字体。web字体需要下载,解析,重绘当前页面
  • 合理使用requestAnimationFrame动画代替setTimeout
  • css中的属性(css3 transitions、css3 3D transforms、opacity、webGL、video)会触发GUP渲染,耗电

8. TCP 传输的三次握手、四次挥手策略

  • 三次握手:

    为了准确无误地吧数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,他一定会向对方确认是否送达,握手过程中使用TCP的标志:SYN和ACK

    • 发送端首先发送一个带SYN的标志的数据包给对方
    • 接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息
    • 最后,发送端再回传一个带ACK的标志的数据包,代表“握手”结束
  • 如在握手过程中某个阶段莫明中断,TCP协议会再次以相同的顺序发送相同的数据包


  • 断开一个TCP连接需要“四次挥手”
    • 第一次挥手:主动关闭方发送一个FIN,用来关注主动方到被动关闭方的数据传送,也即是主动关闭方告诫被动关闭方:我已经不会再给你发数据了(在FIN包之前发送的数据,如果没有收到对应的ACK确认报文,主动关闭方依然会重发这些数据)。但是,此时主动关闭方还可以接受数据
    • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号收到序号 +1(与SYN相同,一个 FIN占用一个序号)
    • 第三次挥手:被动关闭方发送一个 FIN。用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会给你发送数据了
    • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手

9. HTTP 和 HTTPS,为什么HTTPS安全?

  • HTTP协议通常承载与 TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS
  • 默认HTTP的端口号为80,HTTPS的端口号为443
  • 因为网络请求需要中间有很多的服务器路由的转发,中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有,https之所有说比http安全,是因为他利用ssl/tls协议传输。包含证书,流量转发,负载均衡,页面适配,浏览器适配,refer传递等,保障了传输过程的安全性

10. axios和fetch区别对比

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征

  • 从浏览器中创建 XMLHttpRequest
  • 支持 Promise API
  • 客户端支持防止CSRF
  • 提供了一些并发请求的接口(重要,方便了很多的操作)
  • 从 node.js 创建 http 请求
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据

fetch优势:

  • 语法简洁,更加语义化
  • 基于标准 Promise 实现,支持 async/await
  • 同构方便,使用 isomorphic-fetch
  • 更加底层,提供的API丰富(request, response)
  • 脱离了XHR,是ES规范里新的实现方式

fetch存在问题

  • fetch是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装。
  • fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
  • fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
  • fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
  • fetch没有办法原生监测请求的进度,而XHR可以

九、主观题篇

1. 你都做过什么项目呢?具体聊某一个项目中运用的技术.

注意:用心找自己做的项目中自己感觉最拿出来手的(复杂度最高,用的技术最多的项目),描述的时候尽可能往里面添加一些技术名词
布局我们用html5+css3
我们会用reset.css重置浏览器的默认样式
JS框架的话我们选用的是jQuery(也可能是Zepto)
我们用版本控制工具git来协同开发
我们会基于gulp搭建的前端自动化工程来开发(里面包含有我们的项目结构、我们需要引用的第三方库等一些信息,我们还实现了sass编译、CSS3加前缀等的自动化)
我们的项目中还用到了表单验证validate插件、图片懒加载Lazyload插件

2. 你遇到过比较难的技术问题是?你是如何解决的?

3. 常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?

4. 除了前端以外还了解什么其它技术么?你最最厉害的技能是什么?

5. 对前端开发工程师这个职位是怎么样理解的?它的前景会怎么样?

前端是最贴近用户的程序员,比后端、数据库、产品经理、运营、安全都近。
1、实现界面交互
2、提升用户体验
3、有了Node.js,前端可以实现服务端的一些事情
前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好,
参与项目,快速高质量完成实现效果图,精确到1px;
与团队成员,UI设计,产品经理的沟通;
做好的页面结构,页面重构和用户体验;
处理hack,兼容、写出优美的代码格式;
针对服务器的优化、拥抱最新前端技术。

  • 「阻塞策略」:基于脚本加载
  • 「回流重绘策略」:基于回流重绘
  • 「异步更新策略」:基于异步更新

上述五方面都是编写代码时完成,充满在整个项目流程的开发阶段里。因此在开发阶段需时刻注意以下涉及到的每一点,养成良好的开发习惯,性能优化也自然而然被使用上了。

渲染层面性能优化更多表现在编码细节上,而并非实体代码。简单来说就是遵循某些编码规则,才能将渲染层面性能优化发挥到最大作用。

**「回流重绘策略」**在渲染层面性能优化里占比较重,也是最常规的性能优化之一。上年笔者发布的掘金小册《玩转CSS的艺术之美》使用一整章讲解回流重绘,本章已开通试读,更多细节请戳这里。

CSS策略
  • 避免出现超过三层的嵌套规则
  • 避免为ID选择器添加多余选择器
  • 避免使用标签选择器代替类选择器
  • 避免使用通配选择器,只对目标节点声明规则
  • 避免重复匹配重复定义,关注可继承属性
DOM策略
  • 缓存DOM计算属性
  • 避免过多DOM操作
  • 使用DOMFragment缓存批量化DOM操作
阻塞策略
  • 脚本与DOM/其它脚本的依赖关系很强:对``设置defer
  • 脚本与DOM/其它脚本的依赖关系不强:对``设置async
回流重绘策略
  • 缓存DOM计算属性
  • 使用类合并样式,避免逐条改变样式
  • 使用display控制DOM显隐,将DOM离线化
异步更新策略
  • 异步任务中修改DOM时把其包装成微任务

3. 性能优化六大指标

六大指标基本囊括大部分性能优化细节,可作为九大策略的补充。笔者根据每条性能优化建议的特征将指标划分为以下六方面。

  • 「加载优化」:资源在加载时可做的性能优化
  • 「执行优化」:资源在执行时可做的性能优化
  • 「渲染优化」:资源在渲染时可做的性能优化
  • 「样式优化」:样式在编码时可做的性能优化
  • 「脚本优化」:脚本在编码时可做的性能优化
  • 「V8引擎优化」:针对V8引擎特征可做的性能优化

八、其他杂项篇

1. 常见的浏览器内核有哪些?

  • 主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
    • 渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
    • JS引擎则:解析和执行javascript来实现网页的动态效果。
  • 最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
  • 常见内核
    • Trident 内核:IE, MaxThon, TT, The World, 360, 搜狗浏览器等。[又称 MSHTML]
    • Gecko 内核:Netscape6 及以上版本,FF, MozillaSuite / SeaMonkey 等
    • Presto 内核:Opera7 及以上。 [Opera内核原为:Presto,现为:Blink;]
    • Webkit 内核:Safari, Chrome等。 [ Chrome的:Blink(WebKit 的分支)]

2. 网页前端性能优化的方式有哪些?

1.压缩 css, js, 图片
2.减少 http 请求次数, 合并 css、js 、合并图片(雪碧图)
3.使用 CDN
4.减少 dom 元素数量
5.图片懒加载
6.静态资源另外用无 cookie 的域名
7.减少 dom 的访问(缓存 dom)
8.巧用事件委托
9.样式表置顶、脚本置低

3. 网页从输入网址到渲染完成经历了哪些过程?

大致可以分为如下7步:

  • 输入网址;
  • 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
  • 与web服务器建立TCP连接;
  • 浏览器向web服务器发送http请求;
  • web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
  • 浏览器下载web服务器返回的数据及解析html源文件;
  • 生成DOM树,解析css和js,渲染页面,直至显示完成;

4. 线程与进程的区别?

  • 一个程序至少有一个进程,一个进程至少有一个线程.
  • 线程的划分尺度小于进程,使得多线程程序的并发性高。
  • 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  • 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

5. HTTP常见的状态码?

100 Continue 继续,一般在发送post请求时,已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Found 临时性重定向。
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
304 Not Modified 自从上次请求后,请求的网页未修改过。
400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
401 Unauthorized 请求未授权。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。
500 Internal Server Error 最常见的服务器端错误。
503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。

6. 图片懒加载?

当页面滚动的时间被触发 -> 执行加载图片操作 -> 判断图片是否在可视区域内 -> 在,则动态将data-src的值赋予该图片

7. 移动端性能优化?

  • 尽量使用css3动画,开启硬件加速
  • 适当使用touch时间代替click时间
  • 避免使用css3渐变阴影效果
  • 可以用transform: translateZ(0) 来开启硬件加速
  • 不滥用float。float在渲染时计算量比较大,尽量减少使用
  • 不滥用web字体。web字体需要下载,解析,重绘当前页面
  • 合理使用requestAnimationFrame动画代替setTimeout
  • css中的属性(css3 transitions、css3 3D transforms、opacity、webGL、video)会触发GUP渲染,耗电

8. TCP 传输的三次握手、四次挥手策略

  • 三次握手:

    为了准确无误地吧数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,他一定会向对方确认是否送达,握手过程中使用TCP的标志:SYN和ACK

    • 发送端首先发送一个带SYN的标志的数据包给对方
    • 接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息
    • 最后,发送端再回传一个带ACK的标志的数据包,代表“握手”结束
  • 如在握手过程中某个阶段莫明中断,TCP协议会再次以相同的顺序发送相同的数据包


  • 断开一个TCP连接需要“四次挥手”
    • 第一次挥手:主动关闭方发送一个FIN,用来关注主动方到被动关闭方的数据传送,也即是主动关闭方告诫被动关闭方:我已经不会再给你发数据了(在FIN包之前发送的数据,如果没有收到对应的ACK确认报文,主动关闭方依然会重发这些数据)。但是,此时主动关闭方还可以接受数据
    • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号收到序号 +1(与SYN相同,一个 FIN占用一个序号)
    • 第三次挥手:被动关闭方发送一个 FIN。用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会给你发送数据了
    • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手

9. HTTP 和 HTTPS,为什么HTTPS安全?

  • HTTP协议通常承载与 TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS
  • 默认HTTP的端口号为80,HTTPS的端口号为443
  • 因为网络请求需要中间有很多的服务器路由的转发,中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有,https之所有说比http安全,是因为他利用ssl/tls协议传输。包含证书,流量转发,负载均衡,页面适配,浏览器适配,refer传递等,保障了传输过程的安全性

10. axios和fetch区别对比

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征

  • 从浏览器中创建 XMLHttpRequest
  • 支持 Promise API
  • 客户端支持防止CSRF
  • 提供了一些并发请求的接口(重要,方便了很多的操作)
  • 从 node.js 创建 http 请求
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据

fetch优势:

  • 语法简洁,更加语义化
  • 基于标准 Promise 实现,支持 async/await
  • 同构方便,使用 isomorphic-fetch
  • 更加底层,提供的API丰富(request, response)
  • 脱离了XHR,是ES规范里新的实现方式

fetch存在问题

  • fetch是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装。
  • fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
  • fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
  • fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
  • fetch没有办法原生监测请求的进度,而XHR可以

九、主观题篇

1. 你都做过什么项目呢?具体聊某一个项目中运用的技术.

注意:用心找自己做的项目中自己感觉最拿出来手的(复杂度最高,用的技术最多的项目),描述的时候尽可能往里面添加一些技术名词
布局我们用html5+css3
我们会用reset.css重置浏览器的默认样式
JS框架的话我们选用的是jQuery(也可能是Zepto)
我们用版本控制工具git来协同开发
我们会基于gulp搭建的前端自动化工程来开发(里面包含有我们的项目结构、我们需要引用的第三方库等一些信息,我们还实现了sass编译、CSS3加前缀等的自动化)
我们的项目中还用到了表单验证validate插件、图片懒加载Lazyload插件

2. 你遇到过比较难的技术问题是?你是如何解决的?

3. 常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?

常用的库:

  • React.js:用于构建用户界面的JavaScript库。
  • Vue.js:另一个流行的JavaScript框架,用于构建可交互的用户界面。
  • Angular:一个支持大型应用程序开发的完整的JavaScript框架。
  • jQuery:一个简化DOM操作和处理事件的JavaScript库。
  • Lodash:提供了很多实用的功能和工具函数,用于简化JavaScript开发任务。

常用的前端开发工具:

  • Visual Studio Code:一款流行的轻量级代码编辑器。
  • Sublime Text:Sublime Text是一款强大而轻量级的代码编辑器。它具有快速、稳定和高度可定制的特点,支持丰富的插件生态系统,可以满足各种前端开发需求。Sublime Text具有直观的界面、强大的搜索和替换功能、多行选择、语法高亮和自动完成等功能,让前端开发更加高效。
  • WebStorm:WebStorm是一款由JetBrains开发的集成开发环境(IDE)。它专注于提供全面的JavaScript开发体验,适用于前端和后端开发。WebStorm具有强大的代码编辑功能、智能代码完成、错误检查和修复、调试器、Git集成、自动重载和实时预览等功能,能够提供更高效和便捷的前端开发环境。

组件例如:

  • 单页应用(SPA):构建响应式、高度交互的单页Web应用。
  • 表单验证组件:用于验证和处理用户输入的表单组件。
  • 图片轮播组件:用于展示多张图片的轮播效果。
  • 响应式导航菜单:根据不同设备和屏幕大小自适应的导航菜单。
  • 数据可视化组件:用于呈现和展示数据的图表、图形等组件。

4. 除了前端以外还了解什么其它技术么?你最最厉害的技能是什么?

5. 对前端开发工程师这个职位是怎么样理解的?它的前景会怎么样?

前端是最贴近用户的程序员,比后端、数据库、产品经理、运营、安全都近。
1、实现界面交互
2、提升用户体验
3、有了Node.js,前端可以实现服务端的一些事情
前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好,
参与项目,快速高质量完成实现效果图,精确到1px;
与团队成员,UI设计,产品经理的沟通;
做好的页面结构,页面重构和用户体验;
处理hack,兼容、写出优美的代码格式;
针对服务器的优化、拥抱最新前端技术。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/818781
推荐阅读
相关标签
  

闽ICP备14008679号