原型是一种实现对象属性继承和共享机制,它是一个关联到构造函数的.prototype属性的对象,新创建的对象实例会隐式链接到其构造函数的原型,形成了 js 中的原型链继承结构。
原型链是 js 中由对象的原型及其原型的原型逐级向上连接形成的链式结构,用于在对象自身没有某个属性或方法时,按照链式顺序搜索继承的属性和方法。
闭包是指在函数执行完毕后,其内部函数仍能访问该函数作用域内变量的特性。
通过闭包,可以实现私有化变量。
事件循环是一种异步编程模型,会不断地从任务队列中取出任务并放入执行栈执行,直到任务队列为空为止。这种机制保证了 JS 能够在单线程的基础上高效地处理异步操作,避免阻塞主线程。
任务可以分为两类:宏任务和微任务都是异步任务
- 宏任务队列:
setTimeout、setInterval、I/O、UI rendering等。 - 微任务队列:
queueMicrotask、Promise、MutationObserver、async/await、process.nextTick(Node.js)等。
执行流程通常如下:
- 执行全局脚本同步代码,形成执行栈。
- 遇到异步任务时,不阻塞主线程,继续执行后续的同步代码。
待异步任务完成后,其回调函数会被添加到相应的任务队列中等待被执行。 - 当同步代码执行完毕,清空执行栈。
- 检查微任务队列,如果有微任务,执行所有微任务并将它们的结果(如果有)推入新的微任务队列,直到微任务队列为空。
- 渲染 UI(仅在浏览器环境下)。
- 检查宏任务队列,如果有宏任务,取出第一个任务并放入执行栈执行。
- 重复上述步骤。
- 箭头函数没有自己的
this,它们会捕获其所在上下文的this值,因此this的值在箭头函数定义时就已经确定了,不会随着调用方式的改变而改变。而普通函数的this取决于函数的调用方式。 - 箭头函数没有
arguments和super。 - 箭头函数不能用作构造函数,没有
prototype属性,无法访问new.target。使用new调用它们会引发 TypeError。 - 箭头函数不能在其主体中使用
yield,也不能作为生成器函数创建。
const observer = new IntersectionObserver((entries) => {
entries.forEach(change => {
if (change.isIntersecting) {
const img = change.target
if (img.dataset.src) {
img.src = img.dataset.src
observer.unobserve(img)
}
}
})
})
observer.observe(img)- 用户访问 A 系统,没有登录凭证(ticket),自动跳转到 SSO 并附带回调地址
https://sso.com?redirect=a.com/callback - 输入账号密码登录 SSO,账号密码验证成功
- 记录用户在 SSO 的登录状态(cookie 或 token 等方式)
- 下发一个 ticket
- 浏览器被重定向到系统 A 的回调地址,并附带一个 code
https://a.com/callback?code=xxx
系统 A 通过 code 去 SSO 换取 ticket(code 一次性,可以暴露在 URL 中,换完 ticket 就失效) - A 系统拿到 ticket 后,将 ticket 设置到自己域名下的 cookie 里
- A 系统后续请求只需携带 cookie,后台取出 ticket 去 SSO 校验,校验成功后正常处理业务请求
- 然后用户第一次访问 B 系统,没有 ticket,自动跳转到 SSO 并附带回调地址
- SSO 已登录过,直接下发 ticket,步骤同 3-5
- 文件路径中带有 hash 值:一年的强缓存。因为该文件的内容发生变化时,会生成一个带有新的 hash 值的 URL。前端将会发起一个新的 URL 的请求。配置响应头
Cache-Control: public,max-age=31536000,immutable - 文件路径中不带有 hash 值:协商缓存。大部分为 public 下文件。配置响应头
Cache-Control: no-cache与etag/last-modified - 当处理长久缓存时,不能打包为一个大的
bundle.js,因为一行业务代码的改变,将导致整个项目的长久缓存失效,需要按代码更新频率分为多个chunk进行打包,细粒度的控制缓存。
- 更快的渲染速度
- 静态提升:标记不变的静态内容(节点或属性),减少运行时计算和 DOM 操作
- 基于 Proxy 的响应式系统:更细粒度,更高效,支持更多的数据结构
- 更小的体积
- 更好的 TypeScript 支持
- 组合式 API:更加灵活,实现逻辑更易复用
- 高级特性
- Teleport:实现元素在 DOM 树任意位置渲染
- Fragment:允许组件拥有多个根元素
Vue2 在实例初始化时遍历 data 中的所有属性,使用 Object.defineProperty 把这些属性全部转为 getter/setter,getter 中收集依赖,setter 中通知依赖,触发相应的监听回调
- 遍历对象所有属性,如果对象层次较深,性能不好
- 无法监听到通过索引访问数组元素的变化,不支持 Map、Set 等数据结构
- 无法监听动态新增、删除对象属性,只能用特定
$set、$delete的方法
Vue3 使用 Proxy 来监控数据的变化
- Proxy 直接代理整个对象,无需遍历每个属性,并且支持数组、Map、Set 等数据结构
- Proxy 可以拦截包括读取、赋值、删除在内的几乎所有的对象操作
- 延迟加载。例如代理对象的属性 A 也是一个对象,只有 A 被访问时,A 才会被转换为响应式对象,A 内部属性的响应式转换同理
双端比较,相同的节点不动,遇到不同的节点,生成一个数组记录 newChildren 节点在 oldChildren 节点中的索引,如果是新增节点则记为 -1,求出数组的最长递增子序列,这些节点意味着无需移动,仅移动剩余节点和插入新增节点即可。
- Parent
setup - Parent
beforeCreate - Parent
created - Parent
beforeMount- Child
setup - Child
beforeCreate - Child
created - Child
beforeMount - Child
mounted
- Child
- Parent
mounted - Parent
beforeUnmount- Child
beforeUnmount - Child
unmounted
- Child
- Parent
unmounted
如果使用了 KeepAlive
mounted- Child
activated - Parent
activated beforeUnmount- Child
deactivated - Parent
deactivated unmounted
- 初始化参数:Webpack 从配置文件(如
webpack.config.js)和命令行参数中读取配置信息,并合并这些参数以创建最终的构建配置。 - 实例化 Compiler 对象:根据上一步得到的最终配置,Webpack 创建一个 Compiler 对象,这个对象负责整个构建流程的控制。
- 注册插件:Compiler 对象会注册所有配置中指定的插件,这些插件将会监听构建过程中的各种事件钩子(hooks),并在相应阶段执行自定义的逻辑。
- 编译开始:调用 Compiler 对象的
run方法启动编译流程。 - 解析入口文件:根据配置中的
entry属性,Webpack 找到项目的入口起点文件。 - 递归解析依赖:从入口文件开始,Webpack 递归地解析和追踪模块间的依赖关系,这包括 CommonJS、AMD、ES6 模块导入等形式的导入语句。
- 编译模块:对每个模块,Webpack 会按照配置中的 loader 规则,通过调用对应 loader 进行编译转换。Loader 可以用来处理不同类型文件的内容,比如将 TypeScript 转换为 JavaScript,或将 LESS/SCSS 转换成 CSS。
- 生成依赖图:Webpack 将解析到的所有模块及其依赖关系组成一个内部的依赖图,这个图包含了项目中所有模块如何相互关联的信息。
- 优化模块:在依赖图生成之后,Webpack 进行一系列的优化操作,例如代码分割、摇树优化(Tree Shaking)、公共代码提取(CommonsChunkPlugin 或者 SplitChunksPlugin)等。
- 生成 Chunk:根据依赖关系和优化策略,Webpack 将相关模块组合成一个个 Chunk(也就是最终要输出的文件)。
- 输出资源:最后,Webpack 将每个 Chunk 转换成实际的文件内容,并根据配置的
output设置,将这些文件内容写入到磁盘上的指定位置。
- Loader 专注于源文件的转换,应用于单个文件级别,处理模块内容,使其符合模块化标准或转换为另一种格式。
- Plugin 则着眼于整体构建过程的控制与扩展,能够影响多个文件甚至整体构建结果,执行跨模块或与模块无关的操作,如资源管理、优化、环境变量注入、自定义输出等。
- hash:与整个项目有关,项目里有文件修改,所有文件的哈希值都会变化。
- chunkhash:与入口有关,同一入口的文件被视为一个整体,当其中一个文件修改时,同入口的所有文件哈希值发生改变。chunk 有两种,一种是起始入口的 main chunk,另一种是延迟加载的 chunk(动态导入或者 splitChunks 配置)。
- contenthash:只与文件内容有关,文件内容发生改变,才会更改该文件的哈希值。
区块格式化上下文:它定义了一个独立的渲染区域,在这个区域内,内部的盒子(Box)将会按照一套特定的渲染规则进行布局。
BFC 可以用来:
- 包含内部浮动
- 排除外部浮动
- 阻止外边距重叠
/* 表格布局 */
.box {
display: table-cell;
vertical-align: middle;
}
.box .ball {
margin: 0 auto;
}
/* 定位 */
.box {
position: relative;
}
.box .ball {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* 弹性布局 */
.box {
display: flex;
justify-content: center;
align-items: center;
}
/* 网格布局 */
.box {
display: grid;
grid-template-columns: 1fr;
justify-items: center;
align-items: center;
}- 控制视口宽度:
width=device-width表示视口宽度应等于设备的屏幕宽度,即以 CSS 像素(设备独立像素)为单位来设定网页的宽度。在高分辨率的设备上,1px 的 CSS 像素将由大于 1 的物理像素绘制,从而避免出现页面元素缩小的情况。 - 初始缩放比例:
initial-scale=1.0指定页面加载时的初始缩放级别为1.0,也就是说网页加载后原始尺寸将与设备屏幕分辨率保持一致,不进行额外的缩放。