- 看了之后,必须是你理解的。
- 有些时候,作者可能也写错了,我们要有纠错能力
- 有些语言,描述的太啰嗦了,我们需要精简。转换为自己的语言
- 越简洁越好!只要你能够描述清楚
- 遇见问题多动脑子
重绘和重排 ok
重绘:当元素的一部分属性发生改变,
如背景、颜色等不会引起布局变化,
只需要浏览器根据元素的新属性重新绘制,
使元素呈现新的外观叫做重绘。
重排(回流):当render树中的一部分或者全部,
因为大小边距等问题发生改变,而需要DOM树重新计算的过程
所以简单的来说就是。会引起布局的变化,叫做重排(回流)。
不会引起布局的变化,叫做重绘。
『重绘』不一定会出现『重排』,『重排』必然会出现『重绘』。
tip:所以在我们平时写css的时候,还是要按照html中类的顺序来写。
否者可能会造成重排,重排是需要消耗浏览器性能的哈。
引起重排的地方 ok
1.添加、删除可见的dom
2.元素的位置改变
3.元素的尺寸改变(外边距、内边距、边框厚度、宽高)
4.页面渲染初始化
========================
5.浏览器窗口大小改变
6.改变文字大小
7.操作class属性
8.内容的改变,(用户在输入框中写入内容也会)
add,del-->位置-->尺寸--初始化
窗口-->字体-->内容-->操作class属性
如何避免重绘或者重排?ok
#### 1.集中改变样式
#### 2.使用createDocumentFragment
#### 2.使用createDocumentFragment
我们可以通过createDocumentFragment创建一个游离于DOM树之外的节点,
然后在此节点上批量操作,当完成所有的操作后,最后插入DOM树中,这样只触发一次重排
var fragment = document.createDocumentFragment();
for (let i = 0;i<10;i++){
let node = document.createElement("p");
node.innerHTML = i;
fragment.appendChild(node);
}
document.body.appendChild(fragment);
12.前端如何实现即时通讯?
1.短轮询,使用setTimeout。
每隔一段时间客户端就发出一个请求,去获取服务器最新的数据,一定程度上模拟实现了即时通讯。
优点:兼容性强,实现非常简单
缺点:延迟性高,非常消耗请求资源,影响性能
2.Websocket:
Websocket是一个全新的、独立的协议,基于TCP协议。
可以在服务器和客户端之间建立【实时】的【双向通信】。
优点:真正意义上的实时双向通信,性能好,低延迟
缺点:需要额外的项目改造,使用复杂度高,必须引入成熟的库,无法兼容低版本浏览器
3.Web Worker
Web Worker 的作用,就是为 JavaScript 创造【多线程环境】,
允许主线程创建 Worker 线程,将一些任务分配给后者运行
4.Service workers
Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,
也可以在网络可用时作为浏览器和网络间的代理,创建有效的离线体验。
https://www.cnblogs.com/wangxi01/p/11590178.html
13 什么是跨域 ok
协议, 域名, 端口号, 不同就是不同的域。
不同的域之间相互请求资源,就叫“跨域”。
ps:https与http也是不同的域
浏览器基于:“同源策略”
认为跨域请求是不安全的 所以拒绝访问。
14.什么是浏览器同源策略? 理解
同源策略是一个重要的安全策略,
它用于限制一个origin上的文档或者它加载的脚本如何能与另一个源的资源进行交互。
它能阻隔恶意文档,减少被攻击的媒介。
协议, 域名, 端口号 相同就是同源
15 哪三个标签可以不受同源的影响 ok
浏览器中的大部分内容都是受同源策略限制的,但是以下三个标签可以不受限制:
<img src=XXX>
<link href=XXX>
<script src=XXX>
16.如何实现跨域? ok
1.最经典的跨域方案jsonp
2.最流行的跨域方案cors[跨域资源共享]
3.Nginx代理
17.最经典的跨域方案 jsonp
jsonp它利用<script>标签不受同源策略的限制。
缺点:
1.只支持get请求(因为<script>标签只能get)
2.同时需要后配合。
3.有安全性问题,容易遭受xss攻击
2最流行的跨域方案cors[跨域资源共享]
(CORS) 是一种机制,使用 HTTP 头来告诉浏览器。
让运行在一个 origin (domain) 上的Web应用,访问不同源服上务服务的指定的资源。
3.最方便的跨域方案Nginx
Nginx是一款极其强大的web服务器,其优点就是轻量级、启动快、高并发。
反向代理的原理很简单,即所有客户端的请求都必须先经过nginx的处理,
nginx作为代理服务器在将请求转发给node或者java服务,这样就规避了同源策略。
其它跨域方案
1.HTML5 XMLHttpRequest 有一个API,、
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,
可以实现跨文本档、
多窗口、
跨域消息传递。
19 为什么JavaScript是单线程的? 与异步冲突吗 ok
JavaScript是单线程,与它的用途有关。
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
这决定了它只能是单线程,否则会带来很复杂的问题。
解释为什么是单线程的,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,
另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,
这已经成了这门语言的核心特征,将来也不会改变。
不冲突:
Js执行是单线程,但浏览器是多线程,它有以下常驻线程
1.渲染引擎线程:负责页面的渲染。
2.JS引擎线程:负责JS的解析和执行(本文说的主线程就指js引擎线程)
3.定时器触发线程:处理定时事件,比如setTimeout, setInterval
4.事件触发线程:处理DOM事件
5.异步http请求线程:处理http请求
20 异步任务有哪些? ok
1.setTimeOut、setInterval
2.DOM 事件
3.Promise
4.ajax
21. 说一说你对Cookie localStorage sessionStorage ok
Cookie 的缺点:大小,影响性能,安全缺陷
1.Cookie 的体积上限只有4KB,只能用来存储少量的信息。
2.影响性能,不管域名下的某个地址是否需要Cookie,请求都会带上完整的Cookie,请求数量增加,会造成巨大的浪费。
3.安全缺陷,Cookie以纯文本的形式在浏览器和服务器中传递,很容易被非法用户获取,
当HTTPOnly为false时,Cookie信息可以直接通过JS脚本读取。
localStorage:理论上永久有效的,除非主动清除。4.98MB(不同浏览器情况不同,safari 2.49M)
保存在客户端,不与服务端交互。节省网络流量
sessionStorage
仅在当前网页会话下有效,关闭页面或浏览器后会被清除。 4.98MB.(部分浏览器没有限制)
ps==>localStorage其实存储的都是字符串,如果是存储对象需要调用JSON的stringify方法,
在使用的时候用JSON.parse来解析成对象。
23. 谈一谈你对XSS攻击理解?或者 什么是 XSS 攻击? ok
XSS 全称是 Cross Site Scripting ,翻译过来就是“跨站脚本”。
XSS是指黑客往 HTML 文件中注入恶意脚本,
用户在浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
最开始的时候,这种攻击是通过跨域来实现的,所以叫“跨域脚本”。
24. 能不能说一说CSRF攻击
CSRF即跨站请求伪造,黑客诱导用户点击链接,打开黑客的网站,
然后黑客利用用户「目前的登录状态」发起跨站请求。
举个例子, 你在某个论坛点击了黑客精心挑选的小姐姐图片,你点击后,进入了一个新的页面。
那么恭喜你,你可能就被攻击了)
列举如下
<img src="https://xxx.com/info?user=hhh&count=100">
进入页面后自动发送 get 请求,值得注意的是,
这个请求会自动带上关于 xxx.com 的 cookie 信息(这里是假定你已经在 xxx.com 中登录过)。
假如服务器端没有相应的验证机制,它可能认为发请求的是一个正常的用户,
因为携带了相应的 cookie,然后进行相应的各种操作,可以是转账汇款以及其他的恶意操作。
28. DOMContentLoaded 与 load 的区别 ?
DOMContentLoaded事件的触发时机:仅当DOM解析完成后,不包括样式表,图片等资源。
onload 事件触发时机:页面上所有的 DOM,样式表,脚本,图片等资源已经加载完毕。
那么也就是先DOMContentLoaded 实行时机 > load.
那么在Jquery中, document.read(function(){ })监听的就是DOMContentLoaded事件。
使用(document).load(callback)监听的就是load事件。
29. 什么是DOM节点
DOM,即文档对象模型(Document Object Model),W3C 制定的标准规范,
是一种处理 HTML 和 XML 文件的标准 API。
它把文档作为一个树形结构,树的每个结点表示了一个 HTML标签或标签内的文本项。
将 HTML 或 XML 文档转化为 DOM 树的过程称为解析(parse)。
30. 你对addEventListener 来注册事件的理解 ?
我们一般使用 addEventListener 来注册事件,它接受三个参数:
第1个参数:处理的事件名称,如点击事件 click;
第2个参数:事件处理程序,要绑定的函数体;
第3个参数:可以是布尔值,也可以是对象
当第3个参数是布尔值时,true 则作为捕获事件处理,false 则作为冒泡事件处理(默认)。
第三个参数是对象时,有这几个属性:
capture:布尔值,和第三个参数作为布尔值时作用一样
once:布尔值,值为 true 表示该回调只会调用一次,调用后会移除监听
passive:布尔值,值为 true表示永远不会调用 preventDefault.
[如果`listener`仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告]
一般来说,我们可以通过使用 stopPropagation 来阻止事件的进一步传播,即阻止事件冒泡。
32. onclick 与addEventListener的区别
区别 1==>
onclick:就是说相同的事件绑定同一个元素会出现覆盖;
addEventListener:进行多次绑定相同的事件都能运行。不会出现事件覆盖
区别 2==> addEventListener对任何DOM都是有效的。
而onclick仅限于HTML,像br标签使用onclick就是失效。
区别 3==>addEventListener可以控制listener的触发阶段,(捕获/冒泡)。
区别 4==>onclick事件在同一时间只能指向唯一对象
Content [kang 腾 t] 内容、目录、满意
Loaded [ləʊ dɪ d]
33. HTTP 与 HTTPS 的区别
1、HTTP 信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,HTTP是80,HTTPS是443。
4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密、身份认证的网络协议,比 HTTP 协议安全。
(无状态是说:数据包的发送、传输和接收都是相互独立的。
无连接是指:通信双方都不长久的维持对方的任何信息。)
1.浏览器的主要组成部分是什么?ok
1.用户界面:包括地址栏、前进/后退按钮、书签菜单等
2.浏览器引擎:在用户界面和呈现引擎之间传送指令。
3.呈现引擎 :负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
4.网络 :用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现
5.JavaScript解释器:用于解析和执行 JavaScript 代码。
6.数据存储:浏览器需要在硬盘上保存各种数据
2.浏览器是如何渲染UI的? ok
1.浏览器获取HTML文件,然后对文件进行解析,形成DOM Tree.
2.与此同时,进行CSS解析,生成Style Rules
3.接着将DOM Tree与Style Rules合成为 Render Tree
4.接着进入布局(Layout)阶段,为每个节点分配一个应出现在屏幕上的确切坐标。
5.随后调用GPU进行绘制(Paint),遍历Render Tree的节点,并将元素呈现出来
3.浏览器如何解析css选择器?ok
浏览器会『从右往左』解析CSS选择器。
题外话:(1)若从左向右的匹配,(2) 如果从右至左的匹配:
后者匹配性能更好,
是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);
而从左向右的匹配规则的性能都浪费在了失败的查找上面。
4.DOM Tree是如何构建的?()
转码: 浏览器将接收到的二进制数据,按照指定编码格式,转化为HTML字符串
生成Tokens: 浏览器会将HTML字符串,解析成Tokens.
构建Nodes: 对节点(Node)添加特定的属性,通过指针确定节点(Node)的父、子、兄弟关系
生成DOM Tree: 通过node包含的指针信息构建出DOM Tree
巧计:转码-生成Tokens-构建-生成
4. CSS加载会造成阻塞吗 ? ok
CSS不会阻塞DOM解析,但会阻塞DOM渲染。
并不会阻塞JS文件下载,CSS会阻塞JS执行,
4.1 为什么CSS不会阻塞DOM解析,但会阻塞DOM渲染? ok
DOM 和 CSSOM通常是并行构建的,所以「CSS 加载不会阻塞 DOM 的解析」。
然而由于Render Tree 是依赖DOM Tree和 CSSOM Tree的,
所以它必须等到两者都加载完毕后,完成相应的构建。才开始渲染,因此,「CSS加载会阻塞DOM渲染」
CSSOM==》css Object Model [css对象模型]]
5. CSSOM[css对象模型]作用 ? ok
第一个是提供给 JavaScript 操作样式表的能力
第二个是为布局树的合成提供基础的样式信息
6.GUI渲染线程与 JavaScript 引擎(线程)为互斥 ok
我们都知道JavaScript 是可操纵 DOM 和 css 样式 的,
如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),
那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,
浏览器设置 「GUI渲染线程与 JavaScript 引擎为互斥」的关系。
7 为什么有时候JS需要等到CSS的下载呢? Ok
如果脚本的内容是获取元素的样式,宽高等CSS属性
也就是依赖于CSS,因而只好等前面所有的样式下载完后,再执行JS。
34.为什么 0.1+0.1 !== 0.3
在做算术运算时,JS 会先把十进制数转换成二进制数后再计算,
0.1 和 0.2 的二进制数是个无限循环小数。
JS 中表示一个数字只有 64 位,其中精度位(有效数位)只有 52 位,
所以当出现无限循环小数时,会通过 0 舍 1 入 的规则截取前 52 位(类似十进制的四舍五入),
这样导致了精度位的丢失。 所以运算结果不等于 0.3了
35. js表示数字使用64位分别为:
符号位1位:不参与计算,0表示正数;1表示负数;
指数位11位:有个基准值(01111111111),小于这个数时指数位就是负数。
因为指数位没有符号位,而科学计数法的指数位可以为负数。转换的时候要减去这个基准值;
有效位数 52 位:有效数字隐藏了1位,因为以 0 开头没有意义;
36. 什么是vite? 你对vite的理解?
是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:
一个开发服务器,它基于原生 ES 模块。
一套构建指令,它使用 Rollup 打包你的代码。
37. 为什么选择vite?
当我们开始构建越来越大的应用时,
需要处理的 JavaScript 代码量会呈指数级增长。
项目会包含很多的模块。几十个或者几百个。
这个时候我们会遇见性能瓶颈
使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器,
文件修改后的效果也需要几秒钟才能在浏览器中反映出来。
Vite就是为了就解决这个问题
38. vite的优势?
1==>速度快: Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,
并且比 JavaScript 编写的打包器【预构建依赖】快 10-100 倍。
2==>按需提供源码: Vite只需要在浏览器请求源码时,
进行转换并按需提供源码。
根据情景动态导入代码。
40. npm与yarn的区别
1.npm是按照队列执行每个package。
也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。
而yarn是同步执行所有任务,提高了性能。
2.使用yarn安装过一个软件包,再次用yarn安装时,
从缓存中获取,就不会像npm那样再从网络下载了。
package [pai k a g] 包
41. package.json中~和^的区别
波浪号~指定版本:比如 "core-js": "~3.6.5",
表示安装3.6.x的最新版本(不低于3.6.5),
但是不安装3.7.x,也就是说安装时不改变大版本号和次要版本号
^指定版本:比如 "antd": "^3.1.4",
表示安装3.1.4及以上的版本,但是不安装4.0.0,
也就是说安装时不改变大版本号。
形象理解:~向水波一样平静,不改变大版本号和次要版本号.
^ 有冲锋的意思,不改变大版本号
42. vue/cli3.0相对路径打包
没有这个文件需要新增这个文件。在vue.config.js文件中,在跟目录下。
module.exports={
productionSourceMap: false,
publicPath: process.env.NODE_ENV === 'production' ? '././' : './',
}
publicPath的值如果是生产环境(production==>prəˈdʌkʃn),
我们使用././;否者就是开发环境使用./;
如何获取当前的环境呢?process.env.NODE_ENV
process 【ˈprɑːses 】 处理;加工
43. devDependencies和dependencies有何区别
--save-dev等价为-D 意思是开发环境中需要,生产环境中不需要要了
-S 开发和生产环境都需要。
形象记忆:devDependencies 长开发环境
44.js的垃圾回收机制 (面试问过)
找出不再使用的变量,然后释放掉它所占用的内存。
但是这个过程不是时时的,因为其开销比较大。
所以垃圾回收器会按照固定的时间间隔周期性的执行。
从变量的生命周期来讲:
变量分为全局变量和局部变量。
局部变量只在函数执行的过程中存在,一旦函数结束,局部变量就没有存在的必要了。就可以释放掉他们所占用的内存。
垃圾回收机制就必须知道哪些变量有用,哪些变量没有用。
垃圾回收有两种机制:1.标记清除 2.引用计数
45.标记清除
当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为"进入环境",
当变量离开环境的时候(函数执行结束)将其标记为“离开环境"。
原则上讲不能够释放进入环境的变量所占的内存,它们随时可能会被调用的到。
垃圾回收器会在运行的时候给内存中的所有变量加上标记,
然后去掉环境中的变量,以及被环境中所引用的变量(闭包)。
在这些完成之后,仍存在标记的就是要删除的变量。
因为环境中的变量已经无法访问到这些变量了,
然后垃圾回收器相会将这些带有标记的变量所占用的内存空间释放掉.
46.引用计数
引用计数的策略是跟踪记录每个值被使用的次数,
当声明了一个变量并将一个引用类型赋值给该变量的时候,
这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1。
当这个值的引用次数变为0的时候,说明没有变量在使用,
然后垃圾回收器会这个变量所占用的内存空间释放掉.
缺点:没有办法解决循环引用的问题
47.浏览器使用的是那一种垃圾回收?
现在大多数浏览器都是基于标记清除算法。
V8 亦是,当然 V8 肯定也对其进行了一些优化加工处理,
那接下来我们主要就来看 V8 中对垃圾回收机制的优化
48.V8 的垃圾回收策略
V8 的垃圾回收策略主要基于分代式垃圾回收机制。
V8 中将堆内存分为新生代和老生代两区域。采用不同的策略回收垃圾。
新生代指:对象存活时间较短,
简单来说就是新产生的对象,通常只支持 1~8M 的容量,
老生代指:对象的存活时间较长或常驻内存的对象
V8 整个堆内存的大小就等于新生代加上老生代的内存
49.原型
js每声明一个function,都有prototype原型,
prototype原型是函数的一个默认属性,
在函数的创建过程中由js编译器自动添加。
50.原型链:
从实例对象上往上找,找到创造这个实例对象的相关对象。
然后这个相关对象在往上找,找到创造它的,上一级的原型对象.
以此类推,一直到原型对象终止。
51.浏览器缓存机制或者你对浏览器缓存的理解?
浏览器会根据 response header[响应头] 中的 Expires 和cahe-control 字段判断是否命中强缓存,
如若命中,则直接从缓存中取资源,不会再去向服务器请求。
没有命中强缓存,浏览器会发出一个条件请求。
在请求头中包含 If-Modified-Since 或 If-None-Match 字段
If-Modified-Since 即浏览器当初得到的 Last-Modified。If-None-Match即浏览器当初得到的 ETag。(方便自己理解,不需要说出来)
当服务器发现资源的更新时间晚于 If-Modified-Since 所提供的时间。(方便自己理解,不需要说出来)
或者当前的 ETag 和 If-None-Match 提供的不符时,说明该资源需要向服务器重新请求了。
否则,浏览器将不需要重新下载整个资源,只需要从缓存中去加载这个资源,
这时响应的http code 为 304(304 Not Modified)。
参考地址:https://blog.csdn.net/weixin_33895695/article/details/91451701
31. javaScript事件的三个阶段:捕获阶段 目标阶段 冒泡阶段
1.捕获阶段 概念:
事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。
2.目标阶段 概念:
事件到达目标节点时,就到了目标阶段,事件在目标节点上被触发
3.冒泡阶段 概念:
事件在目标节点上触发后,一层层向上冒,回溯到根节点
javascript事件循环机制
javascript是单线程,它只有一条主线.
javascript代码在执行的时候
首先是调用栈,因为耗时较短。
耗时较长的先放置到任务队列中。
任务队列又分为宏任务和微任务。
微任务中队列中放置的是 promise、aysnc、await
宏任务队列中放置的是 setTimeout、 seteral、ajax、onClick 事件
等调用栈的任务执行完成后,再轮询微任务队列,微任务队列中任务执行完成之后再执行宏任务。
不阻塞主进程的程序放入调用栈中,压入栈底,执行完了就会弹出。
而阻塞主进程的程序放入任务队列中,他们需要“排队”依次执行
栈是先进后出,队列是先进先出
1.Set的理解
Set本身是一个构造函数,用来生成Set数据结构。
它类似于数组,但是成员的值是唯一的,不重复的。
set.add(item)加入值。
加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。
[...new Set([1,2,2,3])] //[1,2,3] 数组去重
set.size检测值的个数
map的理解
它类似于对象,也是键值对的集合。
但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
如果对同一个键多次赋值,后面的值将覆盖前面的值。
如果读取一个未知的键,则返回undefined。
new Map().get('userName') // undefined
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。