一、HTML & CSS
布局,比如单位、盒模型、定位、响应式布局等知识点。
1、HTML
1.1 如何理解 HTML 语义化?
- 让人更容易读懂(增加代码可读性)。
- 让搜索引擎更容易读懂,有助于爬虫抓取更多的有效信息,爬虫依赖于标签来确定上下文和各个关键字的权重(SEO)。
- 在没有 CSS 样式下,页面也能呈现出很好地内容结构、代码结构
1.2 script标签为什么要放在底部
因为浏览器在渲染html的时候,从上到下依次执行,遇到js文件就会停止当前页面的渲染,转而去下载js文件,如果将script标签放在头部,如果文件又很大的情况下,首屏时间就会延长,影响用户体验
1.3 script 标签中 defer 和 async 的区别?
-
script
:阻碍 HTML 解析,下载好并执行完脚本才会继续解析 HTML。 -
async script
:解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。 -
defer script
:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。
2、CSS
2.1 CSS 选择器、优先级
推荐文章:
内联 > ID选择器 > 类选择器 > 标签选择器
样式的优先级一般为 !important > style > id > class
优先级是由 A
、B
、C
、D
的值来决定的,其中它们的值计算规则如下:
- 如果存在内联样式,那么
A = 1
, 否则A = 0
; B
的值等于ID选择器(#id)
出现的次数;C
的值等于类选择器(.class)
和属性选择器(a[href="https://example.org"])
和伪类(:first-child)
出现的总次数;D
的值等于标签选择器(h1,a,div)
和伪元素(::before,::after)
出现的总次数
比较规则是: 从左至右比较,如果是样式优先级相等,取后面出现的样式
2.2 CSS 盒模型
developer.mozilla.org/zh-CN/docs/…
CSS3 中的盒模型有以下两种:标准盒模型、IE(替代)盒模型。
两种盒子模型都是由 content + padding + border + margin
构成,其大小都是由 content + padding + border
决定的,但是盒子内容宽/高度(即 width/height
)的计算范围根据盒模型的不同会有所不同:
- 标准盒模型:只包含
content
。 - IE(替代)盒模型:
content + padding + border
。
可以通过 box-sizing
来改变元素的盒模型:
box-sizing: content-box
:标准盒模型(默认值)。box-sizing: border-box
:IE(替代)盒模型。
2.3 对 BFC 的理解
推荐文章:
BFC 即块级格式上下文,根据盒模型可知,每个元素都被定义为一个矩形盒子,然而盒子的布局会受到尺寸,定位,盒子的子元素或兄弟元素,视口的尺寸等因素决定,所以这里有一个浏览器计算的过程,计算的规则就是由一个叫做视觉格式化模型的东西所定义的,BFC 就是来自这个概念,它是 CSS 视觉渲染的一部分,用于决定块级盒的布局及浮动相互影响范围的一个区域。
BFC 具有一些特性:
- 块级元素会在垂直方向一个接一个的排列,和文档流的排列方式一致。
- 在 BFC 中上下相邻的两个容器的
margin
会重叠,创建新的 BFC 可以避免外边距重叠。 - 计算 BFC 的高度时,需要计算浮动元素的高度。
- BFC 区域不会与浮动的容器发生重叠。
- BFC 是独立的容器,容器内部元素不会影响外部元素。
- 每个元素的左
margin
值和容器的左border
相接触。
利用这些特性,我们可以解决以下问题:
- 利用
4
和6
,我们可以实现三栏(或两栏)自适应布局。 - 利用
2
,我们可以避免margin
重叠问题。 - 利用
3
,我们可以避免高度塌陷。
创建 BFC 的方式:
- 绝对定位元素(
position
为absolute
或fixed
)。 - 行内块元素,即
display
为inline-block
。 overflow
的值不为visible
。
2.4 CSS 伪元素和伪类的区别
伪类: 根据文档树中已有元素状态,添加对应样式,如 :hover
、:link
、:active
、:not
、:first-child
等
伪元素: 创建一些不在文档树中的元素,并为其添加样式。如 ::before/:before
、::after/:after
、::first-letter/:first-letter
伪类的操作对象是文档树中已有的元素,而伪元素则创建了一个文档数外的元素。因此,伪类与伪元素的区别在于:有没有创建一个文档树之外的元素。
双冒号 (::) 表示伪元素,伪类使用单冒号 (:)
2.5 水平垂直居中多种实现方式
推荐文章:
-
利用绝对定位,设置
left: 50%
和top: 50%
现将子元素左上角移到父元素中心位置,然后再通过translate
来调整子元素的中心点到父元素的中心。该方法可以不定宽高。.father { position: relative; } .son { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } 复制代码
-
利用绝对定位,子元素所有方向都为
0
,将margin
设置为auto
,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高。.father { position: relative; } .son { position: absolute; top: 0; left: 0; right: 0; bottom: 0px; margin: auto; height: 100px; width: 100px; } 复制代码
-
利用绝对定位,设置
left: 50%
和top: 50%
现将子元素左上角移到父元素中心位置,然后再通过margin-left
和margin-top
以子元素自己的一半宽高进行负值赋值。该方法必须定宽高。.father { position: relative; } .son { position: absolute; left: 50%; top: 50%; width: 200px; height: 200px; margin-left: -100px; margin-top: -100px; } 复制代码
-
利用
flex
,最经典最方便的一种了,不用解释,定不定宽高无所谓的。.father { display: flex; justify-content: center; align-items: center; } 复制代码
其实还有很多方法,比如 display: grid
或 display: table-cell
来做
2.6 实现两栏布局(左侧固定 + 右侧自适应布局)
现在有以下 DOM 结构:
<div class="outer">
<div class="left">左侧</div>
<div class="right">右侧</div>
</div>
复制代码
复制代码
-
利用浮动,左边元素宽度固定 ,设置向左浮动。将右边元素的
margin-left
设为固定宽度 。注意,因为右边元素的width
默认为auto
,所以会自动撑满父元素。.outer { height: 100px; } .left { float: left; width: 200px; height: 100%; background: lightcoral; } .right { margin-left: 200px; height: 100%; background: lightseagreen; } 复制代码
-
同样利用浮动,左边元素宽度固定 ,设置向左浮动。右侧元素设置
overflow: hidden;
这样右边就触发了BFC
,BFC
的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。.outer { height: 100px; } .left { float: left; width: 200px; height: 100%; background: lightcoral; } .right { overflow: auto; height: 100%; background: lightseagreen; } 复制代码
-
利用
flex
布局,左边元素固定宽度,右边的元素设置flex: 1
。.outer { display: flex; height: 100px; } .left { width: 200px; height: 100%; background: lightcoral; } .right { flex: 1; height: 100%; background: lightseagreen; } 复制代码
-
利用绝对定位,父级元素设为相对定位。左边元素
absolute
定位,宽度固定。右边元素的margin-left
的值设为左边元素的宽度值。.outer { position: relative; height: 100px; } .left { position: absolute; width: 200px; height: 100%; background: lightcoral; } .right { margin-left: 200px; height: 100%; background: lightseagreen; } 复制代码
-
利用绝对定位,父级元素设为相对定位。左边元素宽度固定,右边元素
absolute
定位,left
为宽度大小,其余方向定位为0
。.outer { position: relative; height: 100px; } .left { width: 200px; height: 100%; background: lightcoral; } .right { position: absolute; left: 200px; top: 0; right: 0; bottom: 0; height: 100%; background: lightseagreen; } 复制代码
2.7 实现圣杯布局和双飞翼布局(经典三分栏布局)
圣杯布局和双飞翼布局的目的:
- 三栏布局,中间一栏最先加载和渲染(内容最重要,这就是为什么还需要了解这种布局的原因)。
- 两侧内容固定,中间内容随着宽度自适应。
- 一般用于 PC 网页。
圣杯布局和双飞翼布局的技术总结:
- 使用
float
布局。 - 两侧使用
margin
负值,以便和中间内容横向重叠。 - 防止中间内容被两侧覆盖,圣杯布局用
padding
,双飞翼布局用margin
。
圣杯布局: HTML 结构:
<div id="container" class="clearfix">
<p class="center">我是中间</p>
<p class="left">我是左边</p>
<p class="right">我是右边</p>
</div>
复制代码
复制代码
CSS 样式:
#container {
padding-left: 200px;
padding-right: 150px;
overflow: auto;
}
#container p {
float: left;
}
.center {
width: 100%;
background-color: lightcoral;
}
.left {
width: 200px;
position: relative;
left: -200px;
margin-left: -100%;
background-color: lightcyan;
}
.right {
width: 150px;
margin-right: -150px;
background-color: lightgreen;
}
.clearfix:after {
content: "";
display: table;
clear: both;
}
复制代码
复制代码
双飞翼布局: HTML 结构:
<div id="main" class="float">
<div id="main-wrap">main</div>
</div>
<div id="left" class="float">left</div>
<div id="right" class="float">right</div>
复制代码
复制代码
CSS 样式:
.float {
float: left;
}
#main {
width: 100%;
height: 200px;
background-color: lightpink;
}
#main-wrap {
margin: 0 190px 0 190px;
}
#left {
width: 190px;
height: 200px;
background-color: lightsalmon;
margin-left: -100%;
}
#right {
width: 190px;
height: 200px;
background-color: lightskyblue;
margin-left: -190px;
}
复制代码
复制代码
tips:上述代码中 margin-left: -100%
相对的是父元素的 content
宽度,即不包含 paddig
、 border
的宽度。
其实以上问题需要掌握 margin 负值问题 即可很好理解。
2.8 flex 布局
推荐文章:
用过flex布局吗?都有哪些属性?flex: 1代表什么意思?
这里有个小问题,很多时候我们会用到 flex: 1
,它具体包含了以下的意思:
flex-grow: 1
:该属性默认为0
,如果存在剩余空间,元素也不放大。设置为1
代表会放大。flex-shrink: 1
:该属性默认为1
,如果空间不足,元素缩小。flex-basis: 0%
:该属性定义在分配多余空间之前,元素占据的主轴空间。浏览器就是根据这个属性来计算是否有多余空间的。默认值为auto
,即项目本身大小。设置为0%
之后,因为有flex-grow
和flex-shrink
的设置会自动放大或缩小。在做两栏布局时,如果右边的自适应元素flex-basis
设为auto
的话,其本身大小将会是0
。
2.9 line-height 如何继承
- 父元素的
line-height
写了具体数值,比如30px
,则子元素line-height
继承该值。 - 父元素的
line-height
写了比例,比如1.5 或 2
,则子元素line-height
也是继承该比例。 - 父元素的
line-height
写了百分比,比如200%
,则子元素line-height
继承的是父元素font-size * 200%
计算出来的值。
2.10 visibility、display、opacity的区别
2.11 transition、transform、translate的区别
单行截断css
如何画一条 0.5px 的边框
parent元素宽高不定,实现scale固定宽高比始终为4:3
position的几个属性和含义
css和js两种方式实现div右移1000px动画
如何提高动画的渲染性能
二、网络通信
浏览器缓存、Http2.0、Https通信过程、TCP与UDP、DNS解析、CDN缓存等
1、浏览器
onload 和 DOMContentLoaded的区别
requestAnimationFrame
1.1 从浏览器地址栏输入 url 到请求返回发生了什么
推荐文章:
总体来说分为以下几个过程:
-
输入 URL 后解析出协议、主机、端口、路径等信息,并构造一个 HTTP 请求。
- 强缓存。
- 协商缓存。
-
DNS 解析:将域名解析成 IP 地址(字节面试被虐后,是时候搞懂 DNS 了)
-
TCP 连接:TCP 三次握手
总是要问:为什么需要三次握手,两次不行吗?其实这是由 TCP 的自身特点可靠传输决定的。客户端和服务端要进行可靠传输,那么就需要确认双方的接收和发送能力。第一次握手可以确认客服端的发送能力,第二次握手,确认了服务端的发送能力和接收能力,所以第三次握手才可以确认客户端的接收能力。不然容易出现丢包的现象。
-
发送 HTTP 请求
-
服务器处理请求并返回 HTTP 报文
-
浏览器解析渲染页面
-
断开连接:TCP 四次挥手
1.2 cookie、localStorage 和 sessionStorage
- JS存储方式?
- sessionSorage、localstorage、cookie的区别?
- 同一个系统开两个网页,两个网页的sessionStorage共享吗?
cookie:
- 本身用于浏览器和 server 通讯。
- 被“借用”到本地存储来的。
- 可用 document.cookie = '...' 来修改。
- 存储大小限制为 4KB。
- http 请求时需要发送到服务端,增加请求数量。
- cookie设置的过期时间之前一直有效
localStorage 和 sessionStorage:
- HTML5 专门为存储来设计的,最大可存 5M。
- API 简单易用, setItem getItem。
- 不会随着 http 请求被发送到服务端。 区别:
- localStorage 数据会永久存储,浏览器关闭后数据不丢失,除非代码删除或手动删除。
- sessionStorage 数据只存在于当前会话,浏览器关闭则清空。
1.3 重排(reflow)和重绘(repaint)
推荐文章:
简单地总结下两者的概念:
- 重排:无论通过什么方式影响了元素的几何信息(元素在视口内的位置和尺寸大小),浏览器需要重新计算元素在视口内的几何属性,这个过程叫做重排。
- 重绘:通过构造渲染树和重排(回流)阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘。
如何减少重排和重绘?
- 最小化重绘和重排,比如样式集中改变,使用添加新样式类名
.class
或cssText
。 - 批量操作 DOM,比如读取某元素
offsetWidth
属性存到一个临时变量,再去使用,而不是频繁使用这个计算属性;又比如利用document.createDocumentFragment()
来添加要被添加的节点,处理完之后再插入到实际 DOM 中。 - 使用
**absolute**
或**fixed**
使元素脱离文档流,这在制作复杂的动画时对性能的影响比较明显。 - 开启 GPU 加速,利用 css 属性
transform
、will-change
等,比如改变元素位置,我们使用translate
会比使用绝对定位改变其left
、top
等来的高效,因为它不会触发重排或重绘,transform
使浏览器为元素创建⼀个 GPU 图层,这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。
1.5 浏览器的垃圾回收机制
- 你刚刚提到的标记清除法有什么缺点?怎么解决?
- 你刚刚提到的引用计数法有什么缺点吗?
- v8里面的垃圾回收机制是什么?
- v8是怎么解决循环引用的?
推荐文章:你真的了解垃圾回收机制吗
1.6 宏任务、微任务、EventLoop - 需要再整理
- EventLoop中为什么要同时存在宏任务和微任务两个队列?设计一个行不行?一段代码在执行时,程序是如何去区分宏任务和微任务的?
- 微任务的优先级
- 哪些是宏任务?哪些是微任务?
- 如何理解script标签是个宏任务
整理文章 > juejin.cn/post/705235…
1.7 内存泄露
- 项目中内存泄漏的场景
- setTimeout为什么会造成内存泄露?
- 如何防止setTimeout内存泄露?
- 清除定时器为什么就不会有内存泄露?
描述一下同源策略、跨域及其解决方案
- 前端常见跨域解决方案(全)
- 描述Jsonp具体的实现方案
DOM事件模型。事件捕获和事件冒泡的使用场景
2、Http
2.1 http 状态码
状态码分类
- 1xx - 服务器收到请求。
- 2xx - 请求成功,如 200。
- 3xx - 重定向,如 302。
- 4xx - 客户端错误,如 404。
- 5xx - 服务端错误,如 500。
常见状态码
- 200 - 成功。
- 301 - 永久重定向(配合 location,浏览器自动处理)。
- 302 - 临时重定向(配合 location,浏览器自动处理)。
- 304 - 资源未被修改。
- 403 - 没权限。
- 404 - 资源未找到。
- 500 - 服务器错误。
- 504 - 网关超时。
关于协议和规范
- 状态码都是约定出来的。
- 要求大家都跟着执行。
- 不要违反规范,例如 IE 浏览器。
200状态码一定是服务器返回的吗?
不是,命中强缓存的话,会直接从内存或者磁盘中读取资源,并返回一个200状态码,具体操作可以试试浏览器的前进后退键。
2.2 http 缓存
- 哪些字段用做强缓存?哪些字段用做协商缓存?
- cache-control、expires、etag等字段的属性值是什么样的?
- 这些字段都被存放在请求的哪个部分?
- last-modify和expires这些字段的时间有什么区别?
- last-modify和expires能共存吗?
- 如果不想让某个资源使用缓存,那么应该如何设计http缓存?
- cache-control中的no-cache和no-store的区别
- 如何设计css、js等文件的缓存
2.3 HTTP 请求跨域问题
get和post有什么区别?
请求参数:get请求参数是通过url传递的,多个参数以&连接;post请求放在request body中。
请求缓存:get请求会被缓存,而post请求不会,除非手动设置。
相对的安全性:get是将参数通过url传递的,会被浏览器缓存,容易被他人获取,post相对来说,比较安全。
请求参数长度限制:get通过url传参,浏览器会限制url的长度(http不会
)。
编码方式:GET请求只能进行url编码,只能接收 ASCII 字符,而POST支持多种编码方式。
====
- 从幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
- 从 TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
2.4 http1.1和http2.0有什么区别?
http2 的 相 关 特 性 ?
2.5 HTTP 灵魂之问,巩固你的 HTTP 知识体系
http和https的区别?为什么https是相对安全的?https加密原理?
推荐文章:为什么HTTPS是安全的,一张图告诉你
xss和csrf的概念和防御方式
3、其他
DNS解析具体是怎么个解析过程呢
三次握手、四次挥手讲一下
三、JS 基础
原型与原型链、继承、事件循环、作用域、ES6语法、垃圾回收与内存泄漏等。 juejin.cn/post/694094…
1、数据类型
1.1 基本的数据类型介绍,及值类型和引用类型的理解
在 JS 中共有 8
种基础的数据类型,分别为: Undefined
、 Null
、 Boolean
、 Number
、 String
、 Object
、 Symbol
、 BigInt
。
Symbol
和 BigInt
是 ES6 新增的数据类型:
- Symbol 代表独一无二的值,最大的用法是用来定义对象的唯一属性名。
- BigInt 可以表示任意大小的整数。
值类型:是直接存储在 栈(stack) 中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用类型:是存储在 堆(heap) 中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;
1.2 数据类型的判断方式
-
typeof:不可对 null、对象、数组进行精确判断,因为都返回
object
,其他判断都正确console.log(typeof undefined); // undefined console.log(typeof 2); // number console.log(typeof true); // boolean console.log(typeof "str"); // string console.log(typeof Symbol("foo")); // symbol console.log(typeof 2172141653n); // bigint console.log(typeof function () {}); // function // 不能判别 console.log(typeof []); // object console.log(typeof {}); // object console.log(typeof null); // object 复制代码
-
instanceof:只能判断引用数据类型,不能判断基本数据类型。其内部运行机制是判断在其原型链中能否找到该类型的原型。比如考虑以下代码:
class People {} class Student extends People {} const vortesnail = new Student(); console.log(vortesnail instanceof People); // true console.log(vortesnail instanceof Student); // true 复制代码
其实现就是顺着原型链去找,如果能找到对应的
Xxxxx.prototype
即为true
。比如这里的vortesnail
作为实例,顺着原型链能找到Student.prototype
及People.prototype
,所以都为true
。 -
Object.prototype.toString.call() :所有原始数据类型都是能判断的,还有 Error 对象,Date 对象等。
Object.prototype.toString.call(2); // "[object Number]" Object.prototype.toString.call(""); // "[object String]" Object.prototype.toString.call(true); // "[object Boolean]" Object.prototype.toString.call(undefined); // "[object Undefined]" Object.prototype.toString.call(null); // "[object Null]" Object.prototype.toString.call(Math); // "[object Math]" Object.prototype.toString.call({}); // "[object Object]" Object.prototype.toString.call([]); // "[object Array]" Object.prototype.toString.call(function () {}); // "[object Function]" 复制代码
1.3 如何判断变量是否为数组
Array.isArray(arr); // true
arr.__proto__ === Array.prototype; // true
arr instanceof Array; // true
arr.constructor === Array; // true
Object.prototype.toString.call(arr); // "[object Array]"
复制代码
ps:通过instanceof和constructor来判断不一定准确,因为可能会被重写。
1.4 什么是深拷贝和浅拷贝? 以及怎么实现深拷贝和浅拷贝?
1.5 数组的遍历方法有哪些
方法 | 是否改变原数组 | 特点 |
---|---|---|
forEach() | 否 | 数组方法,不改变原数组,没有返回值 |
map() | 否 | 数组方法,不改变原数组,有返回值,可链式调用 |
filter() | 否 | 数组方法,过滤数组,返回包含符合条件的元素的数组,可链式调用 |
for...of | 否 | for...of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象,将异步循环变成同步循环 |
every() 和 some() | 否 | 数组方法,some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false. |
find() 和 findIndex() | 否 | 数组方法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值 |
reduce() 和 reduceRight() | 否 | 数组方法,reduce()对数组正序操作;reduceRight()对数组逆序操作 |
遍历方法的详细解释:《细数JavaScript中那些遍历和循环》
2、原型、原型链
总结
- 当一个对象查找属性和方法时会从自身查找,如果查找不到则会通过__proto__指向被实例化的构造函数的prototype
- 隐式原型也是一个对象,是指向我们构造函数的原型
- 除了最顶层的Object对象没有__proto_,其他所有的对象都有__proto__,这是隐式原型
- 隐式原型__proto__的作用是让对象通过它来一直往上查找属性或方法,直到找到最顶层的Object的__proto__属性,它的值是null,这个查找的过程就是原型链
3、作用域、作用域链含义和使用场景
推荐文章
- 作用域:规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。换句话说,作用域决定了代码区块中变量和其他资源的可见性。(全局作用域、函数作用域、块级作用域)
- 作用域链:从当前作用域开始一层层往上找某个变量,如果找到全局作用域还没找到,就放弃寻找 。这种层级关系就是作用域链。(由多个执行上下文的变量对象构成的链表就叫做作用域链,学习下面的内容之后再考虑这句话)
需要注意的是,js 采用的是静态作用域,所以函数的作用域在函数定义时就确定了。
4、函数执行上下文包含了哪些内容
推荐文章:
总结:当 JavaScript 代码执行一段可执行代码时,会创建对应的执行上下文。对于每个执行上下文,都有三个重要属性:
- 变量对象(Variable object,VO);
- 作用域链(Scope chain);
- this。(关于 this 指向问题,在上面推荐的深入系列也有讲从 ES 规范讲的,但是实在是难懂,对于应付面试来说以下这篇阮一峰的文章应该就可以了:JavaScript 的 this 原理)
5、箭头函数和普通函数有什么区别?
箭头函数比普通函数更加简洁
如果没有参数,就直接写一个空括号即可
如果只有一个参数,可以省去参数括号
如果有多个参数,用逗号分割
如果函数体的返回值只有一句,可以省略大括号
如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。最常用的就是调用一个函数:
let fn = () => void doesNotReturn()
(2) 箭头函数没有自己的this
箭头函数不会创建自己的this,所以它没有自己的this,它只会在自己作用域的上一层继承this。所以箭头函数中的this的指向在它在定义时一家确定了,之后不会改变。
(3)箭头函数继承来的this指向永远不会改变
(4) call()、apply()、bind()等方法不能改变箭头函数中的this指向
(5) 箭头函数不能作为构造函数使用
(6) 箭头函数没有自己的arguments
(7) 箭头函数没有prototype
(8) 箭头函数不能用作Generator函数,不能使用yeild关键字
ES6
Typescript
框架通识
框架的底层原理,React 的知识点有 React diff、生命周期、Fiber 架构、Hooks 等;Vue 的知识点有Vue diff、响应式原理、Vue3.0新特性等
React
Vue
打包工具
Webpack
模块化
性能优化
代码层面:
- 防抖和节流(resize,scroll,input)。
- 减少回流(重排)和重绘。
- 事件委托。
- css 放 ,js 脚本放 最底部。
- 减少 DOM 操作。
- 按需加载,比如 React 中使用
React.lazy
和React.Suspense
,通常需要与 webpack 中的splitChunks
配合。
构建方面:
- 压缩代码文件,在 webpack 中使用
terser-webpack-plugin
压缩 Javascript 代码;使用css-minimizer-webpack-plugin
压缩 CSS 代码;使用html-webpack-plugin
压缩 html 代码。 - 开启 gzip 压缩,webpack 中使用
compression-webpack-plugin
,node 作为服务器也要开启,使用compression
。 - 常用的第三方库使用 CDN 服务,在 webpack 中我们要配置 externals,将比如 React, Vue 这种包不打倒最终生成的文件中。而是采用 CDN 服务。
其它:
- 使用 http2。因为解析速度快,头部压缩,多路复用,服务器推送静态资源。
- 使用服务端渲染。
- 图片压缩。
- 使用 http 缓存,比如服务端的响应中添加
Cache-Control / Expires
常见手写题 & 算法
手写深拷贝
文章推荐:如何写出一个惊艳面试官的深拷贝?
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
* @param {Map} map 用于存储循环引用对象的地址
*/
function deepClone(obj = {}, map = new Map()) {
if (typeof obj !== "object") {
return obj;
}
if (map.get(obj)) {
return map.get(obj);
}
let result = {};
// 初始化返回结果
if (
obj instanceof Array ||
// 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
Object.prototype.toString(obj) === "[object Array]"
) {
result = [];
}
// 防止循环引用
map.set(obj, result);
for (const key in obj) {
// 保证 key 不是原型属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key], map);
}
}
// 返回结果
return result;
}
复制代码
防抖(debounce) 和 节流(throttle)
算法常见:排序、递归、链表、动态规划
参考文章
不断更新ing,如有错误请指正~