前端
2021-07-22 18:09:05 9 举报
AI智能生成
思维导图目录
作者其他创作
大纲/内容
工具
包管理
代码管理
git
rebase
merge
add
checkout
branch
HEAD
^
往后退一步
~
往后退 N 步
revert
reset
cherry-pick
学习Git 网站
自动化构建
webpack
webpack5
模块联邦
插件
Loader
css-loader
style-loader
thread-loader
html-loader
less-loader
postcss-loader
sass-loader
stylus-loader
source-map-loader
HMR
webpack-cli
webpack-dev-server
例子
异步组件
require.ensure
import(/* webpackChunkName: "Async" */ './Async'))
概念
Plugins
DllPlugin
webpack dll
mini-css-extract-plugin
html-webpack-plugin
HardSourceWebpackPlugin
HRM
原理
Babel
AST
AST 语法树是什么
构建AST 语法树
解析
分词通过遍历字符串判断关键词
词法分析阶段把字符串形式的代码 转换为 令牌流 (tokens)
转换
@babel/parse 转化为 AST抽象语法树
@babel/traverse 对 AST 节点进行递归遍历
@babel/types 对具体的 AST 节点进行修改
生成
@babel/generator AST 抽象语法树生成新的符合规范的代码
Plugins
@babel/core
@babel/preset-env
@babel/plugin-proposal-decorators
@babel/preset-react
@babel/plugin-transform-runtime
Docker
镜像
容器
仓库
CI/CD
flow.io
规范化
代码质量管理
Eslint
ci/cd 持续部署集成
微前端
实现方式
icestark
字节落地方案
算法
数据结构
数组
查找
数组连续,效率高,可以迅速定位到数组中某一个节点位置
插入
数组中元素插入会引起被插入位后 所有元素索引的改变
排序
冒泡排序
选择排序
插入排序
希尔排序
快速排序
二分排序
链表
查找
需要通过前一个元素指向下一个元素的地址,需要前后依赖,效率较低
插入
链表只需要改变某一个节点的 next
删除
翻转链表
翻转部分链表
队列
栈
哈希
哈希表
罗马数字转数字
二叉树
BFS(广度优先遍历)
DFS(深度优先遍历)
遍历
前序遍历 (中左右)
中序遍历 (左中右)
后序遍历(左右中)
题目
查找最大值,偶数层,拍平
基础算法
分治
快速排序
从数列中挑出一个元素作为基准。
重新排列数列,把所有的比基准小的放在基准前面,反之放在后面(一样大可任意一边)完成后基准处在分区的中间位置
通过递归调用把小于基准元素和大雨基准元素的子序列进行排序
动态规划
爬楼
卖股票
斐波那契数列
最小路径和
两数之和
最长上升子序列
贪心算法
获取子数组的最大连续子数组的值
树图
算法复杂度
时间复杂度
空间复杂度
图形算法
计算机网络
OSI 7层模型 & TCP 4层模型
OSI 7层模型
应用层
为操作系统或者网络应用程序提供访问网络服务的接口,协议 HTTP HTTPS SMTP POP3 SSH
表示层
把数据转换为接受者能够兼容并且适合传输的内容,比如数据加密,压缩,格式转换等。
会话层
负责数据传输中设置和维持网络设备之间的通信连接。管理主机之间的会话进程,还可以利用在数据中插入校验点来实现数据的同步。
传输层
把传输表头加至数据形成数据包,完成端到端的数据传输。传输表头包含了协议等信息,比如: TCP,UDP
网络层
负责对子网间的数据包进行寻址和路由选择,还可以实现拥塞控制,网际互联等功能。网络层的协议包括:IP,IPX 等。比如路由器就在这
数据链路层
在不可靠的物理介质上提供可靠的传输,主要主要为:物理地址寻址、数据封装成帧、流量控制、数据校验、重发等。比如交换机就在这
物理层
在局域网上传送数据帧,负责电脑通信设备与网络媒体之间的互通,包括针脚,电压,线缆规范,集线器,网卡,主机适配等。
TCP/IP 概念层模型
应用层
TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet,html
网络层
TCP,UDP
传输层
IP,ICMP,RIP,OSPF,BGP,IGMP
链路层
SLIP,CSLIP,PPP,ARP,RARP MTU
状态码
1xx
101 Switching Protocols
意思是 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信 比如更换为Websocket,如果服务器也同意变更,就会发送状态码 101,但之后的数据传输就不会再使用 HTTP
协议升级 主要用于websocket,也可以用于http2的升级。
2xx
200 OK
成功状态码,表示客户端发来的请求被服务器端接收到并正常处理了,通常响应报文伴随 body 数据
204 No Content
表示成功,但返回的响应报文没有 body 数据,也不允许返回 body 数据
206 Partial Content
HTTP 分块下载或断点续传的基础,表示客户端发送了“范围请求” 响应报文包含 “Content-Range”指定响应报文 body 数据的具体范围,供客户端确认 例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计 2000 个字节的前 100 个字节
3xx
301 Movved Permanently
永久性重定向。请求的资源已经分配了新的 URI,以后用新的 URI 访问
302 Found
临时性重定向。请求的资源已被分配了新的 URI,希望本次用新的 URI 访问
301 与 302 比较
301 和 302 都会在响应头里使用 Location 表明后续要跳转的 URI,最终效果相似,浏览器都会重定向到新的 URI,但是语义上有根本的区别,所以用法和场景差距很大
301:比如当前服务做迁移,原来的服务不使用了,所以要配置 301,把所有流量切换到新的服务去
302:比如网站系统需要维护,服务暂时不可用,可以配置 302,把流量临时切换到别的资源去,而浏览器看到 302 时,不会做缓存优化
303 See Other
表示资源存在另一个 URI,应该使用 GET 方法定向获取资源
304 Not Modified
用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制,返回时不包含 body
307 Temporary Redirect
临时重定向。和 302 Found 有着相同含义。尽管 302 标准禁止 POST 变换成 GET,但实际上大家并不遵守 而 307 则遵守浏览器标准,不变换方法
原本的用法是用于让post请求的跳转去新的post请求,但也用于hsts跳转。
原本的用法是用于让post请求的跳转去新的post请求,但也用于hsts跳转。
hsts全称HTTP严格传输安全(HTTP Strict Transport Security,縮寫:HSTS),
功能是要求浏览器下次访问该站点时使用https来访问, 而不再需要先是http再转https。
这样可以避免ssl剥离攻击,
即攻击者在用户使用http访问的过程中进行攻击,
对服务器冒充自己是用户,在攻击者和服务器中使用https访问,在用户和服务器中使用http访问。
具体使用方法是在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age
功能是要求浏览器下次访问该站点时使用https来访问, 而不再需要先是http再转https。
这样可以避免ssl剥离攻击,
即攻击者在用户使用http访问的过程中进行攻击,
对服务器冒充自己是用户,在攻击者和服务器中使用https访问,在用户和服务器中使用http访问。
具体使用方法是在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age
ssl 剥离攻击
大概就是信任第三方的安全证书,这点被利用于代理软件监听https。
大概就是信任第三方的安全证书,这点被利用于代理软件监听https。
308 Permanently Redirect
永久重定向。和 301 Found 有着相同含义。但是类似 307,不允许重定向后的请求变动
4xx
400 Bad Request
表示报文存在语法错误,笼统的报错,不具体
401 Unauthorized
表示发送的请求需要有通过 HTTP 认证的认证信息 若之前进行过 1 次请求,则认证失败。初次接收 401,会弹出认证窗口
403 Forbidden
表示服务器禁止访问资源,请求被拒绝了
404 Not Found
资源在服务器上未找到。也可以在服务器端拒绝请求且不想说明理由时使用
405 Method Not Allowed
不允许使用某些方法操作资源
406 Not Acceptable
资源无法满足客户端请求的条件
408 Request Timeout
请求超时,服务器等待了过长的时间
409 Conflict
多个请求发生了冲突,可以理解为多线程并发时的竞态
413 Reuqest Entity Too large
请求报文里 body 太大
414 Request-URI Too long
请求行里 URI 过长
429 Too Many Requests
客户端发送了太多的请求,通常是由于服务器的限连策略
431 Request Header Fields Too Large
请求头某个字段或总体太大
5xx
500 Internal Server Error
与 400 类似,也是通用错误码,表示服务器发生了错误,笼统的报错,不具体
501 Not Implemented
表示客户端请求的功能还不支持
502 Bad Gateway
一般来说,服务器作为网管或者代理时返回的错误码
503 Service Unavailable
表示服务器当前忙(超负荷),暂时无法响应服务 503 是一个临时的状态,
服务器不那么忙了以后可以继续提供服务
所以响应报文通常会有“Retry-After”字段,表示客户端可以多久后再次尝试发送请求
服务器不那么忙了以后可以继续提供服务
所以响应报文通常会有“Retry-After”字段,表示客户端可以多久后再次尝试发送请求
协议层
TCP / IP
TCP 协议 一次数据传输,从建立连接到断开连接流程
三次握手
第一次client -> server 只能server判断出client具备发送能力
第二次 server -> client client就可以判断出server具备发送和接受能力。
此时client还需让 serve r知道 自己接收能力 没问题于是就有了第三次
此时client还需让 serve r知道 自己接收能力 没问题于是就有了第三次
第三次 client -> server 双方均保证了自己的接收和发送能力没有问题
其中,为了保证后续的握手是为了应答上一个握手,每次握手都会带一个标识 seq,后续的ACK都会对这个seq进行加一来进行确认。
数据传输
四次挥手
Client -> Server A(主动方)发起[1]断开链接的请求告诉A所有数据发送完毕可以关闭接收数据的接口 (只是说明A将要关闭发送接口,此时A正常接收数据)
Server (被动方)接收到请求关闭接收数据的接口
向 Client 发送[2]确认关闭接收数据的接口的消息,叫A不要再次发送关闭链接的请求了。
Client 收到 Server 的确认消息后关闭了发送接口,等待 Server 将所有的数据传输完毕后关闭接口的消息。
Server 如果没有数据传输给 Client 了会 发送[3] 一条关闭发送接口的消息给 Client 让 Server 关闭自己的接收数据的接口。
Server 收到 Client 的消息后会关闭自己的接收数据接口,并且发送[4]一条确认消息告诉 Client 不要再次发送关闭接口的通知了。
HTTP
HTTP 1.0
HTTP 1.1
HTTPS
HTTP2
HTTP3
请求头
Request Header
CDN
CDN 预热
CDN 刷新
DNS
域名解析
网络安全
CSRF
如何防范 CSRF 攻击
XSS
HTTPS
HSTS
强制客户端使用 HTTPS 与 服务器端建立连接
网络安全
抓包工具
小鲨鱼
w2
服务器代理
文章
看完这篇HTTP,跟面试官扯皮就没问题了
基础知识大图
网络架构图
手写面试题
手写面试题
call 实现
1. 获取 上下文作用域 context 如果没有的话,采用 window对象
2. 获取 当前调用call函数的方法,通过this 指针回去到
3. 定义常量Symbol,将方法挂载到 context作用域中
4. 调用方法并且将 除第一个参数后面的参数,放到函数中使用
5. 在 context 对象中 删除 定义的常量Symbol,删除引用
6. 返回函数方法调用的结果
apply 实现
1. 获取 上下文作用域 context 如果没有,采用 window
2. 定义常量Symbol,将 当前调用 apply 函数的方法,通过this 挂载到 context作用域中
3. 调用方法并且将 除第一个参数以外的参数,传入函数中调用
4. 在 context 对象中 删除 定义的常量Symbol,删除引用
5. 返回函数方法调用结果
bind 实现
1. 获取当前的 上下文作用域 context 如果没有的话 采用 window 对象
2. 获取参数,通过 [].prototype.slice(arguments, 1) 方法 将参数取出,并且获取当前调用方法 fn = this
3. bind 返回一个函数并且支持传入拼接新的参数 利用经典继承实现 fn.apply(context, args.concat(newArgs))
4. 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
寄生组合继承
1. 利用经典继承的特点 apply 通过调用 apply 实现 Parent函数执行
2. 通过 Child.prototype = Object.create(Parent.prototype)
3. 将子函数的构造函数 指向当前Child Child.prototype.constructor = Child
ES6继承
1. 利用extends 继承父类
2. 使用 super关键词 调用 父类的函数方法
new 实现
1. 获取构造函数 通过方法 [].prototype.shirt.apply(arguments) 返回值是构造函数 Constructor
2. 新建空对象 obj = Object.create();
3 obj.__proto__ = Constructor.prototype 将空对象的 proto 指向构造函数原型对象
4. 执行函数 Constructor.apply(obj, 剩余的参数)
5. 直接返回函数执行的结果
instanceof 实现
1. 获取左边参数的 proto,获取右边参数的 prototype
2. while 遍历 当前 proto 如果不等于 null,继续将 当前 proto = proto.__proto__ 直到 proto 为null 为止
3. 如果 proto 等于 prototype 那么返回 true
Object.create 实现
1. 创建一个方法函数 function F
2. function F的 原型对象 指向传入的 proto
3. 返回 new F() 函数的实例化
Object.assign 实现
1. 保存第一个对象
2. 双层遍历,将对象中所有的Key 存到 第一个目标对象中
Promise的实现
Promise 实现步骤
定义状态 pending fulfilled rejected
constructor 构造函数执行初始的方法 初始化状态 value reason;
传入的方法 fn 马上执行 传入参数 resolve 和 reject
传入的方法 fn 马上执行 传入参数 resolve 和 reject
getter setter status 当前 status 变成最终态(fulfilled 或者 rejected) 的时候
执行 CALL_BACK_LIST里面全部的方法,并且将 value 或者 reason的值传进去
执行 CALL_BACK_LIST里面全部的方法,并且将 value 或者 reason的值传进去
定义 resolve reject的方法 每次修改状态之前确保状态 是 PENDING的时候
对 status value 或者 reason 进行赋值
对 status value 或者 reason 进行赋值
then 方法 核心方法
处理传入的方法 判断是否为方法 如果不是方法,
修改是默认的方法 value => return value
修改是默认的方法 value => return value
定义一个全新的 promise2 new 当前实例返回
定义当前 微任务的 成功和失败的方法 将 resolve 方法执行 value值的结果 用 x 存起来
继续在 resolvePromise中继续执行 ,拒绝的微任务同理
继续在 resolvePromise中继续执行 ,拒绝的微任务同理
resolvePromise 接收参数有 promise2 x resolve reject
resolvePromise 最复杂的部分 传入 then 方法的Promise2 x resolve reject
比较 Promise2 与 x 如果 Promise2 与 x 相同
则返回错误信息 类型错误 Promise 和 返回值相同
则返回错误信息 类型错误 Promise 和 返回值相同
判断 x 是否属于 当前的 MyPromise 继续递归 x.then 继续执行将返回值
传到 resolvePromise中继续传递
传到 resolvePromise中继续传递
如果是对象 或者是方法
如果 x 是等于 null 返回 resolve返回 value = null
取 then 获取当前 x.then 方法
判断 then 是否是一个方法 如果是
如果 then 是一个方法 定义变量 called 设为 false
判断是否立即执行 then方法 立即执行 同样传入 resolve 和 reject 方法
判断是否立即执行 then方法 立即执行 同样传入 resolve 和 reject 方法
resolve函数的参数是y 如果函数已经被执行过了 立即返回,
如果没有执行将 called 变量设为 true 继续递归执行 resolvePromise
如果没有执行将 called 变量设为 true 继续递归执行 resolvePromise
reject函数的参数是 r 如果函数已经被执行过 立即返回,
如果没有执行将 called 变量设为 true,通过reject方法抛出错误
如果没有执行将 called 变量设为 true,通过reject方法抛出错误
如果在这个过程中出现错误 如果 called 函数已经抛出过异常直接返回
如果没有 执行 reject 方法 抛出错误
如果没有 执行 reject 方法 抛出错误
如果不是一个方法直接执行 resolve(x) 不是 Promise,对象,函数
直接执行 resolve(x) x是 字符串 数字 布尔值 undefined
直接执行 resolve(x) x是 字符串 数字 布尔值 undefined
不是 Promise,对象,函数 直接执行 resolve(x) x是 字符串 数字 布尔值 undefined
catch 方法 then 方法只执行 onRejected 的部分
静态方法 resolve 方法 返回一个 Promise 并且执行
参数中 resolve 方法传入 value 如果它是 Promise 直接返回 Promise
参数中 resolve 方法传入 value 如果它是 Promise 直接返回 Promise
静态方法 reject 方法 返回一个 Promise 并且执行
参数中 reject 方法传入 reason 如果它是 Promise 直接返回 Promise
参数中 reject 方法传入 reason 如果它是 Promise 直接返回 Promise
静态方法 race 方法 返回一个 Promise 并且 Promise.resolve
方法执行一个 Promise 获取它的值 直接传出第一个返回的值 resolve(x)
方法执行一个 Promise 获取它的值 直接传出第一个返回的值 resolve(x)
静态方法 all 方法 返回一个 Promise 利用 Promise.resolve
方法执行一个 Promise 获取它的值传入数组中并且传出 resolve(result)
方法执行一个 Promise 获取它的值传入数组中并且传出 resolve(result)
Ajax 实现
实现防抖函数 debounce
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
防抖专题
返回的是一个函数
传入,fn和delay 时间 使用定时器实现
频繁事件触发
window 的 resize、scroll
mousedown、mousemove
keyup、keydown
实现节流函数 throttle
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
深拷贝
递归的实现方式
存放已经拷贝的对象 用于 循环引用的时候检测
定义深克隆主体方法
判断是否循环引用
遍历 已经存放的拷贝对象
如果当前传入的 对象和 已经拷贝的资源对象相同 直接返回资源对象
定拷贝容器
将拷贝的对象放入 数组中用于循环应用检测
遍历 目标对象,如果目标对象 key 也是对象 进行深拷贝,否则原始类型的值,直接复制
返回最终的结果
数组扁平化的实现
Array.flat
使用 Reduce 实现
函数柯里化
对比函数的参数和当前传入参数
若参数不够就继续递归返回curry
若参数够就调用函数返回相应的值
若参数不够就继续递归返回curry
若参数够就调用函数返回相应的值
使用闭包 每隔一秒打印出来一个数字
通过 let 实现
通过闭包实现
手写一个 jsonp
返回的是一个 Promise
处理传入的参数 url 和 data
遍历 data 中全部数据 以keyValue的方式拼接到 ? 后面
定义 Symbol 类型变量,用作 window callbackName
利用 script 标签不受同源域名限制的特点 将完整的 url 拼接数据 请求
请求成功 通过 Promise resolve 方法返回 数据接口的数据
删除 window[symbolCb], document.body.removeChild(node)
手写 观察者模式
一个数据修改,需要通知所有的订阅者,它发生更改
EventEmitter 实现
emit
on
once
off
生成随机数的各种方法
Math.random
实现数组的随机排序
Math.random
通用的事件侦听器函数
使用迭代的方式 实现 flatten 函数
实现一个 sleep 函数
await方法实现
对象数组去重
for 循环
indexOf
排序后去重
unique API
filter + sort
Object 键值对 keyValue
ES6 Set
Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。
解析 URL Params 对象
http parse 解析 http的请求头数据
模版引擎实现
字符串正则相关
查找字符串中出现最多的字符串
转化为驼峰命名
实现 正则切分千分位
惰性函数
专题
Array
reducer
filter
map
forEach
some
every
each
includes
flat
flatMap
reduceRight
面试题网站
热门面试题
木易杨
前端经典面试题
fucking FrontEnd
all-of-frontEnd
Daily-Interview-Question
前端百问
高频前端面试题汇总之JavaScript篇
Daliy-question
优秀博主 博文
语言层
Javascript
表达式和运算符
**=
typeof
void
Promise
术语
promise 有 then 方法的对象或者函数
thenable 是一个有 then 方法的对象或者是函数
value promise状态成功时候的值 resolve(value) string number bollean undefined thenable promise
reason promise 状态失败时的值 也是 rejected的值 Reject(reason)
exception 使用 throw 抛出去异常
Promise 规范
Promise status
Pending
初始状态,可以改变
Promise 被 resolve 或者 reject 之前 都是处于这个状态
通过 resolve -> fulfilled
通过 reject -> rejected
Fulfilled
最终的状态 不可以被改变.
一个 promise 经过 resolve后 变成这个状态
必须有一个 value 值 不传的话 就是 undefined
Rejected
最终的状态 不可以被改变.
一个 promise 经过 reject 变成这个状态
必须有一个 reason 值 不传的话 就是 undefined
then
参数要求
onFulfilled 必须是函数 如果不是函数,应该被忽略
onRejected 必须是函数类型 如果不是函数 应该被忽略
onFulfiilled 特性
在promise变成 fulfilled 时候 调用onFulfilled 参数是 value
在promise 变成 fulfilled 之前不应被调用
只能被用一次
onRejected 特性
onFulfilled 和 onRejected 应该是微任务
queueMicroStask
then 方法可以被调用多次
promise 变成 fulfilled 后 onFulfilled 的回调都应该按照 then的顺序执行
promise.then(cb1).then(cb2).then(cb3)
promise.then(cb1).then(cb2).then(cb3)
在实现 promise的时候 需要一个数组来存储 onFufilled cb
promise 变成 rejected 后 onRejected 的回调都应该按照 then的顺序执行
在实现 promise的时候 需要一个数组来存储 onRejected cb
在实现 promise的时候 需要一个数组来存储 onRejected cb
then 返回值 是一个 promise
onFulfilled 或者 onRejected 执行结果为x 调用 resolvePromise
onFulfilled 或者 onRejected 执行异常 调用 promise2 需要 rejected
如果 onFufilled 不是一个函数 promise2 以 promise1 value 触发 fulfilled
如果 onRejected 不是一个函数 promise2 以promise1 reason 触发 rejected
resolvePromise
如果 promise2 和 x 相等,那么reject TypeError. 直接Rejected 出来
如果 x 是一个 Promise
如果 x 是 pending 直到 x 变成 fulfilled \/ rejected
如果 x 是 fulfilled fulfill promise with the same value
如果 x 是 rejected reject promise with the same reason
resolvePromise(promise2, x, resolve, reject)
如果 x 是一个 object 或者是一个 function
那么就 let then = x.then;
如果 x.then 这一步出错 try catch(e) reject(e);
如果 then 是一个 函数 then.call(x, resolvePromise, rejectPromise)
resolvePromiseFn 参数 y 执行 resolvePromise(promise2, y, resolve, reject)
如果 调用then的时候出现错误的话 就 调用 rejected
如果 调用then的时候出现错误的话 就 调用 rejected
实现Promise
const promise = new Promise(); 代表 Promise 应该是一个构造函数或者class
定义三种状态 pending fulfilled rejected
初始化状态
实现 resolve reject 方法
这两个方法要更改 status 从 pending变更 fulfilled / reject
入参 分别 是 value / reason.
实例化传参
入参 是函数
接收 resolve 和 reject 两个参数
初始化 promise的时候 需要同步执行函数,有错误的时候马上抛出 reject 中接收
then方法
then 接收两个参数 onFulfilled 和 onRejected
检查并处理参数,如果参数不是函数的话 就忽略掉
根据当前 Promise状态 调用不同的函数
首先我们要拿到所有的回调,新建2个数组 分别存储失败和成功的回调,调用 then 如果还是pending状态,就存入数组
在status 发生变化的时候,执行回调,用到es6 getter 和 setter 监听状态
then返回值
如果 onFulfilled 活着 onRejected 抛出一个异常e,那么新的 promise 必须 rejected
return 返回值应该是一个 Promise
如果 onFulfilled 不是函数,且 Promise1 成功执行,Promise2 必须返回同样的状态 和 Value
如果 onRejected 不是函数,且 Promise1 拒绝执行, Promise2 必须返回同样的状态和 Value
如果 onFulfilled 或者 onRejected 返回一个值 x , 运行 resolvePromise 方法
resolvePromise (最难的部分 处理边界值 逻辑判断 例如 区分 Promise Number Object 数据类型)
onFulfilled 和 onRejected 在微任务里面执行
Promise 状态流
Promise局限性
ES6
定义
泛指 2015年 ES2015 官方名称(每年6月进行改动)以后版本
声明
let
块级作用域
没有变量提升
暂时性死区
const
块级作用域
暂时性死区
必须变量初始化
不可重新复制改地址值
复杂数据类型,可以索引更改值
Object.freeze 深度冻结数据
初始化的时候必须复制,不能分开初始化和赋值
箭头函数
语法糖
const fn = a => a
const sum = (a, b) => a + b
this 指向
this 指向箭头函数 所在的作用域
声明未知的参数
剩余的参数 ...args
转为逗号分隔开的参数序列
类数组 转 数组
合并数组
内置对象扩展
Array
构造函数方法Array.from()
实例方法
find(),findIndex(),includes()
String
模版字符串
`${解析变量}`
`${调用函数()}`
`可换行`
实例方法
startsWith(),endsWith(),repeat()
解构匹配赋值
数组
对象
技巧 key解构
使用场景
变量交换
Set 数据结构
本质是构造函数,可传数组
实例方法
add,delete,clear,是否有该值的has
可用forEach遍历
Class 类
语法糖
管理私有变量
Get/Set 优缺点
实现私有变量
建立只读变量 js 如何建立只读变量
封装核心 适配器模式的实现
静态方法
Web APIS
BOM浏览器对象
window
核心API
alert
confirm
prompt
open
onerror
addEventListener
setTimeout
setInterval
窗口位置
screenLeft
screenTop
screenX
screenY
moveBy(x,y)
moveTo(x,y)
窗口大小
innerWidth
innerHeight
outerWidth
outerHeight
resizeTo(width, height)
resizeBy(width, height)
定时器
setTimeout
setInterval
location
hash
host
hostname
href
pathname
port
protocol
search
navigation
screen
width
height
availWidth
availHeight
availLeft
availTop
colorDepth
pixelDepth
history
go
back
forword
length
pushState
onPopState
DOM 文档对象
面向对象
对象含义
对象是对于单个物体的抽象方法
对象是一个容器,封装了属性和方法
属性: 对象的状态
方法: 对象的行为
构造函数
目的:生成对象
需要一个模版 表正一类物理的共同特征,从而生成对象
类即是对象的模板
js 本质上不是基于类,而是基于构造函数 + 原型链
constuctor + prototype
特点
函数体内使用 this this指所要生成的实例
生成对象通过 new 来实例化
可以做初始化传参
构造函数,不初始化, 无法使用
兼容方法
new
创建空对象,作为返回的对象实例
将生成空对象的原型对象指向了构造函数的prototype属性
将当前实例对象赋给了内部的this
执行构造函数初始化代码
new 实现源码实现
源码实现
实例对象
实例对象属性互不影响
通过构造函数实例化(new)出来的对象
它继承了 构造函数中的属性和方法
实例对象的 constructor 属性 指向 构造函数的引用 这个属性继承自原型对象
实例对象的 __proto__ 指向 构造函数的 prototype属性 (原型对象)
constructor
每个对象创建的时候会自动拥有一个构造函数属性 constructor
constructor 继承自原型对象的,指向构造函数的引用
存在的问题
构造函数中的方法,会存在于每个生成的实例中 通用的方法没办法通用
prototype 原型对象
构造函数:用来初始化创建对象的函数 - Course
自动给构造函数赋予一个 prototype,该属性实际等于实例对象的原型对象
实例对象:course1 实例对象,根据原型创建出来的实例
每个对象都有 __proto__
每个实例对象都有 constructor属性,constructor 又继承而来,并且指向当前的构造函数
原型对象:Course.prototype
继承
目的
在原型对象的所有属性和方法,都能被实例所共享
原型链继承
父类属性一旦赋值给子类的原型属性,此时属性就 属于子类的共享属性
实例化子类的时候,不能向父类传参
经典继承
经典继承,在子类的构造函数中调用父类的构造函数
原型链上的共享方法无法被读取继承,如何解决呢?
组合继承
无论什么场景都会调用两次父类构造函数
初始化子类原型时 new的时候
子类构造函数内部call父类的时候
寄生组合继承
利用 Object.create API 避开 new 构造函数执行多一次
多重继承方式
利用 Object.assign 组合多个对象
原型链 关系图
作用域
作用域链
演示代码
图形
this
this 指的是 上下文 context
函数直接调用 this 指向的是 window
this 是在执行时候动态读取上下文决定的
隐式调用
this 指向的是调用堆栈的上一级
在执行函数时候,如果函数被上一级所调用,那么上下文(this)指向上一级
例子1
例子2
例子3
否则则为全局孤立,指向window
显式绑定
bind
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
arg1,arg2...
返回值
返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
绑定函数也可以使用 new 运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的 this 值会被忽略,但前置参数仍会提供给模拟函数。
用法
偏函数
配合 setTimeout
作为构造函数使用的绑定函数
快捷调用
快捷调用2
Polyfill
原理
bind 属于 Function.prototype
apply
func.apply(thisArg, [argsArray])
thisArg
argsArray
返回值
调用有指定this值和参数的函数的结果。
用法
快捷调用
快捷调用(因为它支持数组的参数传递)
使用apply来链接构造器
你可以使用apply来链接一个对象构造器 (en-US),创建一个全局Function 对象的construct方法 ,来使你能够在构造器中使用一个类数组对象而非参数列表
call
function.call(thisArg, arg1, arg2, ...)
thisArg
arg1,arg2...
使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
用法
使用 call 调用 父构造函数
call 调用匿名函数
使用 call 方法调用函数并且制定上下文的 this
使用 call 方法调用函数并且不指定第一个参数(argument)
new
this 指向 new 出来的实例
优先级
new > 显式 > 隐式 > 默认
例子
闭包
函数作为返回值场景
函数外部获取到了函数作用域内的变量值
函数作为参数
函数嵌套
事件处理(异步执行)的闭包
立即执行函数,调用外部作用域的 i,i值不会被垃圾回收机制回收
使用 let 设置块级作用域变量
立即执行嵌套
立即执行遇上块级作用域
a 不会被垃圾回收,依然引用外部作用域参数 a
拆分执行 多个闭包
应用
实现私有变量
跨域
jsonp
jsonp 原理
jsonp 优缺点
jQuery的 jsonp 形式
cors
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。
Access-Control-Allow-Origin 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
postMessage
页面和其打开的新窗口的数据传递
多窗口之间消息传递
页面与嵌套的iframe消息传递
上面三个场景的跨域数据传递
websocket
客户端
服务器端
Node 中间件代理
实现原理
例子
nginx 反向代理
实现原理
修改 nginx 配置 就可以轻松实现
window.name + iframe
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
a.html 与 b.html 是同域,c是不同域名
location.hash + iframe
实现原理
一开始a.html给c.html传一个hash值
然后c.html收到hash值后,再把hash值传递给b.html
最后b.html将结果放到a.html的hash值中。
同样的,a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000
实现步骤
a.html
b.html
c.html
document.domain + iframe
实现原理
a.html
b.html
浏览器开启跨域
严格模式
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀 0 表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用 fn.caller 和 fn.arguments 获取函数调用栈
增加 保留字段 static interface protected
请求
XMLHttpRequest
fetch
AbortController
预编译
创建ao对象
找形参和变量的声明 作为ao对象的属性名 值是 undefined
实参和形参相统一
找函数声明 会覆盖变量的声明
开始执行 JS
CSS
意料之外的 CSS知识
盒子模型
CSS选择器
BFC
position
position 定位
一直不知道 fixed 布局 是基于 document.body 进行相对定位 脱离文档流
flex布局
CSS 优先级
圣杯布局和 双飞翼布局
CSS3 新特性
CSS 样式隔离
CSS 性能优化
层叠上下文
div实现居中
史上最全 div 居中方法
浮动
CSS属性
outline
outline 属于在一条声明中设置 多个轮廓属性的 简写属性
HTML
模块化
模块化 本质
模块化的本质上 是一种提供对外通信接口,进行代码切分/组成的管理方式,其呈现的方式因不同的模块化方案而不同,基本是以文件粒度区分
模块化的历史
函数之间互相调用
命名空间
巧用闭包
依赖注入
模块化技术方案介绍
IIFE
使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突
umd
不支持代码切割
AMD
使用requireJS 来编写模块化,特点:依赖必须提前声明好 (依赖前置)
CMD
使用seaJS 来编写模块化,特点:支持动态引入依赖文件 代表 Sea.js
CMJ(CommonJS)
值拷贝,同步执行的,有引用缓存,判断当前是否已经引用过这个模块,如果应用过直接返回
require 方法加载数据,一般用在 Node 环境,小程序 也是 reuquire
循环引用问题
文件是一个模块 ,私有。内置两个 变量 module require (exports = module.exports)
esm
编译分为三个阶段
实例化阶段,构建依赖图
静态分析 编译的时候,import export default 通过依赖构建出链图(所以 eslint等 规范会推荐将 import等内容写在文件开头的位置),最后通过 module recall 记录文件信息,文件内存地址
编译的时候就能知道 哪些依赖使用了哪些依赖是没有使用,这样可以做 tree-shaking
没有循环引用的问题
生成依赖图以后,需要入口文件,必须指定入口文件
加载阶段,加载对应的资源
开始执行代码 求值,内存中存储,所以是引用拷贝的
执行阶段
源码实现
设计模式
理论基础
设计协作
组织模块
提高代码质量
工具
系统
五大设计原则
开闭原则(OCP)
开:拓展
闭:修改关闭
单一职责原则 (SRP) 模块
功能点 拆分为两个不同的类 互相不耦合
区分多个模块,区分开,将模块传入到 其他模块然后再进行实例化
依赖倒置原则(DIP)
上层不应该依赖下层的实现
动态注入,动态加载
接口隔离原则(ISP)接口的独立
类方法进行一个细化
接口隔离开来
里氏替换原则 LSP
子类在系统中可以替代父类 覆盖父类中的方法 子类是可拓展
父类出现的地方,子类就一定可以出现
子类不能改变
23种设计模式
创建型模式
工厂模式
批量生产相同类型应用满足 频繁使用同一种类型需求
建造者模式
当我们需要模块化拆分一个大模块,同事使模块之间独立解耦分工(header)拆分多个
单例模式
全局只需要一个实例,注重统一一体化(路由Router)
结构型(代码结构)
适配器模式
中间转换参数,保持模块间独立
装饰器模式
附再 多个组件上 批量动态赋予功能的时候
代理模式
将代理对象与调用对象分离,不直接调用目标对象
命令型
模板模式
通过模板定义执行顺序,独立操作
观察者模式
通过观察者 可以被观察者统一发生变化,触发相应的依赖值统一更新
职责链模式
单元链式调用执行,操作流程
Typescript
基础知识
enum 枚举
相同类型的常量组合在一起 就是枚举
type
标识数据 类型
interface
标识数据结构
|
(联合类型 一次只能使用一种类型,而交差类型 每次都市 多个类型的合并类型)
&
(联合类型 一次只能使用一种类型,而交差类型 每次都市 多个类型的合并类型)
typeof
标识 数据类型
keyof
可以获取对象中 所有的 key 值
in
用来遍历枚举类型
extends
T extends Interface 继承类型
Paritial
Paritial<T> 的作用是将某个类型的属性全部变为可选项
Required
Required<T> 作用是 将 interface 泛型 变成 必填
Readonly
Readonly<T> 作用是将 interface 泛型中 全部变为只读
Record
Record<K extends keyof any, T>作用是将K中的所有的属性的值,转化为T类型
Exclude
Exclude<T, U> 将某个类型中属于另一个类型移除掉
Extract
Extract<T, U> 作用是从T中取出U,大概的意思是 取 T 和 U 交集
react 实战 应用
React + Typescript 应用
浏览器
性能优化
评价指标
首次绘制 First Paint/FP
第一次看到白屏时间
首次内容绘制 First Contentful Paint/FCP
第一次看到文本/svg/canvas
FCP 一般和 FP仅仅相差几秒,太久说明网络连接 或者 index.html 太过庞大
首次有意义绘制 First Meaningful Paint / FMP
重要头部图片 这是 chromium 计算到所有布局中最大变化布局绘制完毕的时间
时间久可能是太多的资源(图片,样式,字体)阻塞
可交互时间 TTI
页面布局已经稳定 关键的页面字体已经可见 用户可以在 UI上进行点击和交互
交互响应
用户输入到响应用户操作所需要的时间
目标
响应时间 应该少于 100ms
谷歌研究的说明,切换路由的时候小于 100ms 用户都是不会又负反馈
帧率 60 FPS
网络
HTTP2
OCSP stapling
Online Certificate Status Protocol
服务器先去 CA指定的 OCSP URL 获取 OCSP 查询结果,并且将结果直接发送给客户端,免去客户端再去 CA服务器验证的动作,实现加速 TLS握手
CDN
加载策略
首屏CSS
将首屏 css 内联添加到页面 head中 从而减少往返请求
由于慢启动阶段交换包的大小有限,所以关键的 CSS预算大约是 14kb
减少无关 http 请求
JavaScript 合并 code-spliting
css sprite
image base 64 位
HTTP2 新特性意味着 上述优化不再适用
HTTP/2 支付覆盖率问题,还需要实际权衡
懒加载
字体
异步脚本
图片懒加载
SPA路由
选项卡数据
资源压缩
gzip
brotli
brotli 默认参数,有比gzip 更加好的压缩率
css 压缩
js 压缩
img 压缩
视频压缩
dns-prefetching
<link rel="dns-prefetch" href="www.google-analytics.com">
允许浏览器在用户浏览页面的时候在后台运行 DNS解析,这样用户在点击一个连接时候 已经 dns解析完成
preconnect
<link rel="preconnect" href="cdn.domain.com">
允许浏览器在 HTTP 请求正式发给服务器之前 预先执行一些操作,包括 DNS解析 TLS 协商 TCP握手等,这些消除了往返延迟 并为用户节省了时间
preload
<link rel="preload">
proload 专注于 当前页面并且 以高优先级加载
preload 不会阻塞 window onload 事件
prefetch
<link rel="prefetch">
prefetch 专注于下一个页面 并以低优先级 加载
浏览器在页面加载完成后,利用空闲 时间提前获取用户未来可能会访问的内容
开发策略
html
减少 dom 数量
减少 iframe 使用
性能慢
阻塞load事件
css
尝试不引入第三方库
复用Class
内联关键样式
css 替代图片,比如三角形
CSS containment
新的 CSS 属性 Containment 允许开发者限制浏览器样式,布局和paint 工作的范围,而不是默认全局
webpack 打包移除 未使用的 css
减少 css 文件大小
JavaScript
尝试使用原生的 JavaScript
减少定义全局变量
节流
防抖
defer
延迟顺序执行
评论框
语法高亮
async
立即下载延后无序执行
统计代码量
Cookies
去除不必要 Cookie
尽量压缩使用 cookie
图片
http clients hints
浏览器主动将一些特性告诉服务端,以便服务端更有针对性输出内容,比如不同分辨率的图片
图床
webp
ssr
AMP
在谷歌搜索结果中快速展示
打包策略
purify css
清除没有使用的 css
tree-shaking
移除JavaScript 上下文中未引用的代码 dead-code
code-spliting
把代码分割成 chunk 特定情况下按需加载
缓存策略
缓存设置
强缓存
协商缓存
Service workers
实现离线页面
缓存中 尽可能多的缓存资产,字体,样式,js和图像
性能监控
per-moniter
在浏览器输入 URL 回车之后发生了什么(超详细版)
URL 解析
首先判断你输入的是一个合法的 URL 还是一个待搜索的关键词,并且根据你输入的内容进行自动完成、字符编码等操作。
由于安全隐患,会使用 HSTS 强制客户端使用 HTTPS 访问页面。详见:你所不知道的 HSTS。
HSTS
浏览器还会进行一些额外的操作,比如安全检查、访问限制
检查缓存
DNS查询
浏览器缓存
操作系统缓存
路由器缓存
ISP DNS 缓存
根域名服务器查询
递归方式:一路查下去中间不返回,得到最终结果才返回信息(浏览器到本地DNS服务器的过程)
迭代方式,就是本地DNS服务器到根域名服务器查询的方式。
什么是 DNS 劫持
前端 dns-prefetch 优化
TCP 连接
应用层:发送 HTTP 请求
在前面的步骤我们已经得到服务器的 IP 地址,浏览器会开始构造一个 HTTP 报文,其中包括:
请求报头(Request Header):请求方法、目标地址、遵循的协议等等
请求主体(其他参数)
其中需要注意的点:
浏览器只能发送 GET、POST 方法,而打开网页使用的是 GET 方法
请求报头(Request Header):请求方法、目标地址、遵循的协议等等
请求主体(其他参数)
其中需要注意的点:
浏览器只能发送 GET、POST 方法,而打开网页使用的是 GET 方法
传输层:TCP 传输报文
传输层会发起一条到达服务器的 TCP 连接,为了方便传输,会对数据进行分割(以报文段为单位),并标记编号,方便服务器接受时能够准确地还原报文信息。
在建立连接前,会先进行 TCP 三次握手。
在建立连接前,会先进行 TCP 三次握手。
网络层:IP协议查询Mac地址
将数据段打包,并加入源及目标的IP地址,并且负责寻找传输路线。
判断目标地址是否与当前地址处于同一网络中,是的话直接根据 Mac 地址发送,否则使用路由表查找下一跳地址,以及使用 ARP 协议查询它的 Mac 地址。
判断目标地址是否与当前地址处于同一网络中,是的话直接根据 Mac 地址发送,否则使用路由表查找下一跳地址,以及使用 ARP 协议查询它的 Mac 地址。
链路层:以太网协议
以太网协议
根据以太网协议将数据分为以“帧”为单位的数据包,每一帧分为两个部分:
标头:数据包的发送者、接受者、数据类型
数据:数据包具体内容
标头:数据包的发送者、接受者、数据类型
数据:数据包具体内容
Mac 地址
以太网规定了连入网络的所有设备都必须具备“网卡”接口,数据包都是从一块网卡传递到另一块网卡,网卡的地址就是 Mac 地址。每一个 Mac 地址都是独一无二的,具备了一对一的能力。
广播
发送数据的方法很原始,直接把数据通过 ARP 协议,向本网络的所有机器发送,接收方根据标头信息与自身 Mac 地址比较,一致就接受,否则丢弃。
注意:接收方回应是单播。
注意:接收方回应是单播。
处理请求
大致流程
HTTPD
最常见的 HTTPD 有 Linux 上常用的 Apache 和 Nginx,以及 Windows 上的 IIS。
它会监听得到的请求,然后开启一个子进程去处理这个请求。
它会监听得到的请求,然后开启一个子进程去处理这个请求。
处理请求
接受 TCP 报文后,会对连接进行处理,对HTTP协议进行解析(请求方法、域名、路径等),并且进行一些验证:
验证是否配置虚拟主机
验证虚拟主机是否接受此方法
验证该用户可以使用该方法(根据 IP 地址、身份信息等)
验证是否配置虚拟主机
验证虚拟主机是否接受此方法
验证该用户可以使用该方法(根据 IP 地址、身份信息等)
重定向
假如服务器配置了 HTTP 重定向,就会返回一个 301永久重定向响应,浏览器就会根据响应,重新发送 HTTP 请求(重新执行上面的过程)。
URL 重写
然后会查看 URL 重写规则,如果请求的文件是真实存在的,比如图片、html、css、js文件等,则会直接把这个文件返回。
否则服务器会按照规则把请求重写到 一个 REST 风格的 URL 上。
然后根据动态语言的脚本,来决定调用什么类型的动态文件解释器来处理这个请求。
以 PHP 语言的 MVC 框架举例,它首先会初始化一些环境的参数,根据 URL 由上到下地去匹配路由,然后让路由所定义的方法去处理请求。
否则服务器会按照规则把请求重写到 一个 REST 风格的 URL 上。
然后根据动态语言的脚本,来决定调用什么类型的动态文件解释器来处理这个请求。
以 PHP 语言的 MVC 框架举例,它首先会初始化一些环境的参数,根据 URL 由上到下地去匹配路由,然后让路由所定义的方法去处理请求。
浏览器接受响应
浏览器接收到来自服务器的响应资源后,会对资源进行分析。
首先查看 Response header,根据不同状态码做不同的事(比如上面提到的重定向)。
如果响应资源进行了压缩(比如 gzip),还需要进行解压。
然后,对响应资源做缓存。
接下来,根据响应资源里的 MIME 类型去解析响应内容(比如 HTML、Image各有不同的解析方式)。
首先查看 Response header,根据不同状态码做不同的事(比如上面提到的重定向)。
如果响应资源进行了压缩(比如 gzip),还需要进行解压。
然后,对响应资源做缓存。
接下来,根据响应资源里的 MIME 类型去解析响应内容(比如 HTML、Image各有不同的解析方式)。
渲染页面
HTML 解析
解码(encoding)
传输回来的其实都是一些二进制字节数据,浏览器需要根据文件指定编码(例如UTF-8)转换成字符串,也就是HTML 代码。
预解析(pre-parsing)
预解析做的事情是提前加载资源,减少处理时间,它会识别一些会请求资源的属性,比如img标签的src属性,并将这个请求加到请求队列中。
符号化(Tokenization)
符号化是词法分析的过程,将输入解析成符号,HTML 符号包括,开始标签、结束标签、属性名和属性值。
它通过一个状态机去识别符号的状态,比如遇到<,>状态都会产生变化。
它通过一个状态机去识别符号的状态,比如遇到<,>状态都会产生变化。
构建树(tree construction)
在上一步符号化中,解析器获得这些标记,然后以合适的方法创建DOM对象并把这些符号插入到DOM对象中。
子主题
浏览器容错进制
你从来没有在浏览器看过类似"语法无效"的错误,这是因为浏览器去纠正错误的语法,然后继续工作。
事件
当整个解析的过程完成以后,浏览器会通过DOMContentLoaded事件来通知DOM解析完成。
CSS 解析
CSS 匹配规则
在匹配一个节点对应的 CSS 规则时,是按照从右到左的顺序的,例如:div p { font-size :14px } 会先寻找所有的p标签然后判断它的父元素是否为div。
所以我们写 CSS 时,尽量用 id 和 class,千万不要过度层叠。
所以我们写 CSS 时,尽量用 id 和 class,千万不要过度层叠。
渲染树
计算
通过计算让任何尺寸值都减少到三个可能之一:auto、百分比、px,比如把rem转化为px。
级联
浏览器需要一种方法来确定哪些样式才真正需要应用到对应元素,所以它使用一个叫做specificity的公式,这个公式会通过:
然后得出一个权重值,取最高的那个。
然后得出一个权重值,取最高的那个。
标签名、class、id
是否内联样式
!important
渲染阻塞
当遇到一个script标签时,DOM 构建会被暂停,直至脚本完成执行,然后继续构建 DOM 树。
但如果 JS 依赖 CSS 样式,而它还没有被下载和构建时,浏览器就会延迟脚本执行,直至 CSS Rules 被构建。
所有我们知道:
但如果 JS 依赖 CSS 样式,而它还没有被下载和构建时,浏览器就会延迟脚本执行,直至 CSS Rules 被构建。
所有我们知道:
CSS 会阻塞 JS执行
CSS 资源排在 JavaScript 资源前面
JS 会阻塞后面的 DOM 解析
JS 放在 HTML 最底部,也就是 </body>前
布局与绘制
确定渲染树种所有节点的几何属性,比如:位置、大小等等,最后输入一个盒子模型,它能精准地捕获到每个元素在屏幕内的准确位置与大小。
然后遍历渲染树,调用渲染器的 paint() 方法在屏幕上显示其内容。
然后遍历渲染树,调用渲染器的 paint() 方法在屏幕上显示其内容。
合并渲染层
把以上绘制的所有图片合并,最终输出一张图片。
回流与重绘
回流(reflow)
当浏览器发现某个部分发现变化影响了布局时,需要倒回去重新渲染,会从html标签开始递归往下,重新计算位置和大小。
reflow基本是无法避免的,因为当你滑动一下鼠标、resize 窗口,页面就会产生变化。
reflow基本是无法避免的,因为当你滑动一下鼠标、resize 窗口,页面就会产生变化。
重绘(repaint)
改变了某个元素的背景色、文字颜色等等不会影响周围元素的位置变化时,就会发生重绘。
每次重绘后,浏览器还需要合并渲染层并输出到屏幕上。
回流的成本要比重绘高很多,所以我们应该尽量避免产生回流
每次重绘后,浏览器还需要合并渲染层并输出到屏幕上。
回流的成本要比重绘高很多,所以我们应该尽量避免产生回流
display:none 会触发回流,而 visibility:hidden 只会触发重绘。
JavaScript 编译执行
流程图
词发分析
JS 脚本加载完毕后,会首先进入语法分析阶段,它首先会分析代码块的语法是否正确,不正确则抛出“语法错误”,停止执行。
分词,例如将var a = 2,,分成var、a、=、2这样的词法单元。
解析,将词法单元转换成抽象语法树(AST)。
代码生成,将抽象语法树转换成机器指令。
预编译
创建执行上下文
创建变量对象
建立作用域链
确定 This 指向
执行
JS 引擎线程:也叫 JS 内核,负责解析执行 JS 脚本程序的主线程,例如 V8 引擎
事件触发线程:属于浏览器内核线程,主要用于控制事件,例如鼠标、键盘等,当事件被触发时,就会把事件的处理函数推进事件队列,等待 JS 引擎线程执行
定时器触发线程:主要控制setInterval和setTimeout,用来计时,计时完毕后,则把定时器的处理函数推进事件队列中,等待 JS 引擎线程。
HTTP 异步请求线程:通过XMLHttpRequest连接后,通过浏览器新开的一个线程,监控readyState状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待JS引擎线程执行。
注:浏览器对同一域名的并发连接数是有限的,通常为 6 个。
流程图
浏览器存储
Cookies
localstorage
sessionStorage
indexedDB
Application Cache
浏览器存储
主流浏览器内核
浏览器渲染过程
浏览器通讯
优化工具和途径
浏览器事件模型
事件流
window
document
html
body
div
button
模型
捕获阶段
document -> body -> div -> button
目标阶段
目标阶段会触发元素(currentTarget)上所有的监听器
冒泡阶段
button -> div -> body -> document
注意点 ie8以及以下的 只有冒泡阶段的事件流
addEventListener & removeEventListener
type 事件类型 字符串
listener 函数
options
capture
once
passive
signal
useCapture
true 代表在 捕获阶段触发,false 代表在冒泡阶段触发,默认是false
对于事件目标上的事件监听器来说,事件会处于“目标阶段”,而不是冒泡阶段或者捕获阶段。
在目标阶段的事件会触发该元素(即事件目标)上的所有监听器,
而不在乎这个监听器到底在注册时useCapture 参数值是true还是false。
在目标阶段的事件会触发该元素(即事件目标)上的所有监听器,
而不在乎这个监听器到底在注册时useCapture 参数值是true还是false。
兼容 IE 6- 8
Event.preventDefault
如果此事件没有被显式处理,它默认的动作也不应该照常执行
在文本编辑域中阻止有效的文本输入
选中复选框是点击复选框的默认行为
兼容 IE 6 - 8
Event.stopPropagation
阻止捕获和冒泡阶段中当前事件的进一步传播
兼容 IE 6- 8
事件模型特殊情况
mouseenter & mouseover
mouseenter 事件不会冒泡 当鼠标从外部的元素进入内部的元素的时候触发
mouseover 鼠标光标进入内部时触发
性能监控
Perform API
性能检测库
开发框架
Vue
Vue面试题
React 与 Vue diff 算法 有何不同?
nextTick 原理 实现源码
Virtual DOM
比较两个 DOM 树 差异
mvvm的原理或者核心模式观察模式的实现、如何实现响应式
defineProperty (defineReactive)
vue脚手架新建项目的时候,runtime only or runtime + compiler 有何区别?
beforeCreate 和 created之间做了什么二者有什么区别
props和data是如何把属性挂载在vm上的
vm.$option 为什么data是函数,而components是对象
data函数如果没有返回值会报错么
data函数如果没有返回值会报错么
beforeDestroy 和 destroyed之间做了什么二者有什么区别
vue的实例为何不能挂载在body或者html根节点上,如果挂了会报错吗
beforeMount 和 mounted
虚拟节点是什么,简述虚拟dom构成,vue和react虚拟dom的区别
Vue 双向数据绑定原理
手写 mini Vue
Vue 2.6 源码
文件目录
compiler
编译相关
core
Vue 核心代码组成
platforms
跨平台代码
server
服务器端渲染
sfc
.vue 文件解析器
shared
共享工具方法
初始化
initMixin
init
lifeCycle
events
render
callHooks beforeCreate
inject
state
provide
callHooks created
stateMixin
$set
defineReactive
ob.dep.notify()
$delete
delete target[key]
ob.dep.notify()
$watch
new Watcher
用法
eventsMixin
$on
$emit
$off
$once
LifeCycleMixin
$forceUpdate
vm._watcher.update()
$destroy
callHook beforeDestroy
vm._watcher.teardown()
vm.__patch__(vm._vnode, null)
callHook destroyed
_update
mountComponent
renderMixin
installRenderHelpers
安装依赖,将方法安装到实例中
按需加载
实际应用 sdk 初始化
initApp 初次进入的时候 初始化 在页面逻辑之前安装
$nextTick
nextTick
_render
生成 vNode
数据更新
vm.$mount(vm.$options.el) 实例挂载
根节点校验
判断是否存在 render方法
是 render 转化为 compileToFunction
否 调用 $mount 方法 调用 mountComponent
call beforeMount
new Watcher
pushTarget 把自身实例放入全局 Target
updateComponent
vm._update 虚拟DOM更新真实的 DOM
vm.__patch__
createPatchFunction
patchVnode
createElm
native createELement 生成实际DOM
createChildren 遍历子节点
createElm
invokeCreateHooks
vm._render 实例生成虚拟DOM(vNode)
createElement
normalizeChildren 统一为 vNode 类型
new vNode
tag 为字符串
parsePlatformTagName
createComponent
vNode
未知节点
tag 是 Component 类型 createComponent
call mounted
组件化
组件渲染
createComponent
组件配置
initInteralComponent
/src/core/util/options.js
mergeOptions
响应式原理
依赖收集
initState => initProps/initState
new Dep
new Watcher
pushTarget => 把自身的实例放入全局 target
depend => addDep
把实例 挂载到 dep 的 subs 列表中
traverse
class watcher
observe => new Observer
new Dep
def(obj, __ob, value)
defineReactive
notify()
执行 subs 中 每个 watcher 的 update
派发更新
DOM diff
先找对应的 el
优先处理特殊场景
再考虑原地复用
Vue 3.0 源码
vue3 源码
Vue 路由
路由地址
React
React
基础 API
Suspense
createElement
cloneElement
Hooks
什么是 Hooks
React Hooks 是一种能让你在函数组件中使用state和组件生命周期的一种方式
在Hooks出来之前,你必须把函数组件改成class组件才能用到这些特性
而且,Hooks特性是完全兼容老版本代码的,所以不会对已有代码造成任何影响。并且官网也不推荐为了用Hooks而重构老代码
Hooks 分类
State Hooks
useState
设置和改变 state,代替原来的 state 和 setState
作用域
State Hook 每一次都会直接替换掉旧的state
每一次render的时候都会通过闭包获取一个全新的state引用 (上一次render时替换的新值)
Effect Hooks
useEffect
引入具有副作用的操作,类比原来的生命周期
特点
Effect Hook 的执行时机是在 每一次DOM更新之后进行,
也就是其实 useEffect 会记住你传入的方法,然后每一次render执行完之后都会调用
也就是其实 useEffect 会记住你传入的方法,然后每一次render执行完之后都会调用
其实每一次更新其实我们都是创建了一个新的方法。所以如果有清理操作,每一次更新之前都会进行清理,
而不是只在 unmount 的时候进行清理
而不是只在 unmount 的时候进行清理
useEffect 其实是异步执行的,并不会阻塞DOM更新!
而传统的通过 componentDidMount 或者 componentDidUpdate 进行副作用的操作其实会阻塞DOM的更新
而传统的通过 componentDidMount 或者 componentDidUpdate 进行副作用的操作其实会阻塞DOM的更新
清理 Effect Hooks
具体的时机是 每一次render前都会清理上一次的effects
useEffect 是每一次都会创建一个新的方法,每次render都会调用一遍,
所以清理操作也是每次render都需要做的,而不是仅仅在 unmount 才做
所以清理操作也是每次render都需要做的,而不是仅仅在 unmount 才做
有一个小技巧,如果有一个Effect 只想运行一次,那么直接传一个空数组即可。
useLayoutEffect
与 useEffect 作用相同,但它会同步调用 effect
其他
useContext
上下文爷孙组件及更深层组件传值
useReducer
代替原来 redux 里的 reducer,方便管理状态逻辑
useRef
返回一个可变的 ref 对象
useRef 的内容
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值
useCallback
类似 useMemo,useMemo 优化传值,usecallback 优化传入的方法
useMemo
可根据状态变化控制方法执行,优化无用渲染,提高性能
Hook 实现原理
React 实现Hook的基本原理,是通过一个数组记录,必须严格保证调用顺序始终不变。
在组件中用Hook,每个组件其实都有隔离的state
Custome Hook
Custom Hook 也有一个自己独立的隔离的环境,并不会和调用他的组件共享
Custom Hook 不仅有隔离的环境,并且每一次调用都会创建隔离的环境。
所有的Hooks其实执行原理都一样,Custom Hook 和 内置的 useState/useEffect 等没有本质区别
通过 Custom Hook 封装复用业务逻辑
封装 用户的登录状态
ahooks
swr 请求 hooks
为什么 需要 Hooks 特性
最重要的原因是为了解决逻辑复用的问题,相比对 HoC 或者 render props,他能用更少更简洁的代码实现逻辑复用
规范
放在顶层代码,不要放在任何循环、条件、嵌套分支中,原因后面会讲到
只能从react组件调用Hooks,不要在其他自定义函数中调用Hook
React会给Custom Hook创建隔离的环境,所以他在运行时,显然和我们调用其他的自定义函数是有区别的,这也是为什么我们的Hook必须以 “use” 开头,不能随便取名字,不然React就不知道函数到底是不是Hook了,毕竟他们在JS语法上没区别
Hooks 库
images hooks
Diff 算法
地址
官方文档
React面试题
组件基础
React事件机制
React的事件和普通的HTML事件有什么不同
React 组件中怎么做事件代理的?原理是什么?
React 高阶组件,React props,hooks有什么区别,为什么需要不断迭代
React-Fiber 理解 它解决了什么问题
React.Component 和 React.PureComponent 区别
Component,Elements,Instance 之间有什么区别和联系
React.createClass 和 extends Component 区别有哪些
React 高阶组件是什么,和普通组件有什么区别,适用于什么场景
对 ComponentWillReceiveProps 理解
哪些方法会触发 React 重新渲染?重新渲染 render 会做些什么?
React 如何判断什么时候 重新渲染组件
React 声明组件有哪几种方法,有什么不同的?
对有状态组件和无状态组件的理解以及使用场景是什么
React Fragment的理解,它的使用场景是什么?
React 如何获取组件对应的 DOM 元素
React 中 可以 render 中访问 refs吗 为什么
对React的插槽(Portals)理解,如何使用,有哪些使用的场景
React 中 如何避免不必要的 render
React-Intl的理解 工作原理是什么
React context 理解
为什么 React 并不推荐优先考虑使用 Context
React中 什么是受控组件 和 非控组件?
React中 refs 作用是什么?有哪些使用场景
React 中 除了在构造函数中绑定 this,还有别的方法吗?
React组件的构造函数有什么作用,它是必须的吗?
React.forwardRef 是什么?它有什么作用
类组件与函数组件有什么异同?
React的函数式组件和类组件之间根本的区别: 在心智模型上。
函数式组件经常被忽略的点:函数式组件捕获了渲染所用的值。
状态同步问题,函数组件会捕获当前渲染时,所用的值
函数组件useEffect与类组件生命周期
性能优化
代码复用上差异
React 合成事件
合成事件与原生事件区别
事件名称命名方式不同
事件处理函数写法不同
阻止默认行为方式不同
React 事件与原生事件执行顺序
React 所有事件都挂载在 document 对象上
当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件
执行原生事件,然后处理 React 事件
真正执行 document 上挂载的事件
合成事件的事件池
当事件池未满时,React 创建新的事件对象,派发给组件
当事件池装满时,React 从事件池中复用事件对象,派发给组件
合成事件池实现
数据管理
React setState 调用原理
React setState 调用之后发生了什么 是同步还是异步的
setState 以后 React 更新调度过程
在 setTimeout等 宏任务的异步代码中是 同步的,在宏任务的同步代码中是异步的
面试题
React中的setState 批量更新的过程是什么
React中有使用过 getDefaultProps吗 它有什么作用
React中setState的第二个参数作用是什么
React的setState和replaceState 区别是什么
React组件的this.state和setState有什么区别
React中组件的 this.state 和 setState 有什么区别
state 是怎么注入到组件的,从reducer到组件 经历了什么样的过程
React组件的state和props有什么区别
React中的props为什么是只读的
React中的组件的props改变时 更新组件有哪些方法
React中怎么检验 props 验证props的目的是什么
路由
React-Router的实现原理是什么
如何配置 React-Router 实现路由切换
React-Router怎么设置重定向
React-router 里面的 Link标签和 a标签的区别
React-Router 如何回去 URL的参数和历史对象
React-Router 4 怎么在路由发生变化的时候重新熏染同一个组件的
React-Routert 路由有几种模式
React-Router 4 Switch有什么作用
生命周期
React的生命周期有哪些
React 废弃了哪些生命周期?为什么
React 16.x 中 props 改变后在哪个生命周期中处理
React 性能优化在哪个生命周期?它优化的原理是什么
state 和 props 触发更新的生命周期分别有什么区别
React中发起网络请求 应该在哪个生命周期中进行?为什么?
React 16中新生命周期有哪些
组件通信
父子组件如何通信方式
跨级组件通信方式
非嵌套关系组件的通信方式
如何解决 props 层级过深的问题
组件通信的方式有哪些
Redux
对 Redux的理解 主要解决了什么问题
Redux 原理以及工作流程
Redux中的异步请求怎么处理
Redux 怎么实现属性传递,介绍一下原理
Redux中间件是什么 接收几个参数 柯里化函数两端的参数具体是什么
Redux 请求中间件如何处理并发
Redux状态管理器和变量挂载到 window中有什么 区别
mobox 和 redux 有什么区别
Redux 和 Vuex 有什么区别 它们的共同思想
Redux 中间件是怎么拿刀 store 和 action 然后怎么处理
Redux 中的connect 有什么作用
Hooks
对 React Hook 理解 它的实现原理是什么
为什么 useState 要使用数组而不是对象
对象不方便命名
React Hooks 解决了哪些问题
函数组件代码逻辑复用的问题
useEffect 与 useLayoutEffect 区别
useEffect 在渲染时是异步执行,要等到浏览器将所有变化渲染到屏幕后才会被执行。
useLayoutEffect 会在 浏览器 layout 之后,painting 之前执行,
可以使用 useLayoutEffect 来读取 DOM 布局并同步触发重渲染
尽可能使用标准的 useEffect 以避免阻塞视图更新
useLayoutEffectDestory -> useLayoutEffect -> 渲染 -> useEffectDestory -> useEffect
useMemo 和 useEffect 的区别
useMemo 看起来和 useEffect 很像,但是如果你想在 useMemo 里面 setCount 或者其他修改了 DOM 的操作,那你可能会遇到一些问题。因为传入 useMemo 的函数会在渲染期间执行,你可能看不到想要的效果,所以请不要在这个函数内部执行与渲染无关的操作
useMemo 还返回一个 memoized 值,之后仅会在某个依赖项改变时才重新计算 memoized 值
useMemo 代码用例
React Hooks 在平时开发中需要注意的问题
React Hooks 与生命周期之间的关系
useEffect 与 闭包的思考
useEffect 执行过程
执行 APP 函数
获取 state 最新的值
操作数据 setState 函数 进入 Effects 队列
返回 VDOM
VDOM 渲染 成 DOM
从 Effects 中 取出 操作数据函数,根据条件决定是否执行
虚拟DOM
虚拟DOM的理解 虚拟DOM主要做了什么?虚拟DOM本身是什么
React Diff 算法原理
React Key 是干嘛用的 为什么要加 Key?Key主要是解决什么问题
虚拟DOM 引入与直接操作原生DOM相比 哪个效率更加高 为什么?
React 与 Vue diff 算法 有何不同?
其他
React组件命名推荐的方式是哪个
React 最新版本解决了什么问题,增加了哪些东西
React 如何实现一个 全局的 dialog
React 数据持久化 有什么实践方式吗
React 和 Vue的理解 它们的异同
Typescript 写 React
React 设计思路 它的理念是什么
React 中 props.children 和 React.children 区别
React 状态提升是什么 实用场景有哪些
React constructor 和 getInitialState 区别
React 严格模式如何实用 有什么用处
React 中遍历的方法有哪些
map
forEach
for(let item of items){}
React 中页面重新加载时怎么保留数据
同时引用 react.js react-dom 和 babel 它们都有什么作用
React 必须实用 JSX吗
为什么实用jsx组件中没有看到实用 react 却需要引入 react
React中 怎么使用 async/await
React.Children map 和 js方法中的 map 有什么区别
React SSR理解
为什么 React 要用 JSX
HOC 相比 mixins 有什么 优缺点
React 中高阶组件运用了什么设计模式
React 组件库
Naive UI
semi design
React 源码
preact 参考
源码阅读
relyzer
react 源码解读
彻底搞懂 react 源码
Hooks
React 脚手架
react + ts
NodeJS
简单介绍
nodejs 安装
nodejs 版本切换
包管理工具 npm
nodejs 底层依赖
nodejs 内置模块
封装 Promise方法 将 nodejs 同步文件方法 改成 Promise
CommonJS 详解和源码分析
周边工具介绍解析
Nodejs 如何debug & 内存泄漏
另外一种JS 解析引擎 quickjs
服务端环境demo
基础模块
Buffer
ArrayBuffer
Unit8Array
ArrayBuffer 和 TypedArray 之间的关系
Stream
Writeable
Readable
Duplex
Global
Buffer
console
setTimeout&clearTimeout
setInterval&clearInterval
process
Events
事件执行过程
timer
pending callbacks
idle prepare
poll 执行 与 i/O 相关回调
check
setImmediate 回调
close
MVVM & MVC & MVP
多端开发
小程序
小程序的渲染流程图
H5
React Native
Flutter
hybrid
unity
调试方式
Raxjs
https://rax.js.org/
组件库
KISSY
面试题
0 条评论
下一页