一、html
1.语义化标签
- 代码结构清晰,易于阅读,利于开发和维护
- 方便其他设备解析(如屏幕阅读器)根据语义渲染网页。
- 有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重
2.重绘、重排
-
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘
- 改变元素的 color、background、box-shadow 等属性
-
重排:当 DOM 的变化影响了元素的几何信息(DOM 对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置
- 添加或者删除可见的 DOM 元素
- 元素尺寸改变——边距、填充、边框、宽度和高度
-
优化:
- 尽量使用 position:absolute 或 fixed 元素,不影响其他元素
- 动画开启 GPU 加速(transform、translate),减少触发重绘重排
- 样式集中修改
- 缓存需要修改的 DOM 属性,减少 DOM 操作
- 分离读写操作
二、css
1、盒模型
由 content + padding + border + margin 构成,允许我们在其它元素和周围元素边框之间的空间放置元素
2、BFC
- www.cnblogs.com/xiaozhi6666…
- 布局规则:
- 块级元素沿垂直方向排列
- 内部相邻容器的
margin会重叠 (创建新的 BFC 外部容器;用 padding 代替;设置 border 透明) - 每个元素的左
margin值和容器的左border相接触 - BFC 是独立的容器,容器内部元素不会影响外部元素
- 计算 BFC 的高度时,需要计算浮动元素的高度
- BFC 区域不会与浮动的容器发生重叠
- 创建 BFC 的方式
- 绝对定位元素(position 为 absolute 或 fixed )
- 行内块元素,即 display 为 inline-block
- overflow 的值不为 visible
3、居中布局
- flex 布局
- transform + absolute
- absolute,所有方向为 0,margin:auto
4、清除浮动
- 触发父级 BFC,添加 overflow 属性
- 利用伪类
- 给父类添加固定高度
三、js
1、闭包
- www.ruanyifeng.com/blog/2009/0…
- 定义及用途:
- 读取其它函数内部的变量
- 让这些变量的值始终保持在内存中
- 缺点及注意:
- 闭包会使得函数中的变量都被保存在内存中,消耗内存
- 闭包会在父函数外部,改变父函数内部变量的值。当把父函数当作对象使用,将闭包当作它的公用方法,把内部变量当作它的私有属性,不要随便改变父函数内部变量的值
2、原型、原型链
3、数据类型
3.1 基本数据类型
string、number、boolean、null、undefined、object(function、array)、symbol(ES10 BigInt)
- null 表示空对象 undefined 表示已在作用域中声明但未赋值的变量
3.2 数据类型判断
- typeOf:能判断所有值类型,函数。不可对 null、对象、数组进行精确判断,因为都返回 object
返回值有
string、boolean、number、function、object、undefined - instanceof:能判断对象类型,不能判断基本数据类型,判断该对象是谁的实例
4、作用域、作用域链、变量提升
- 作用域:规定了如何查找变量,也就是确定当前执行代码对变量的访问权限(全局作用域、函数作用域、块级作用域)
- 作用域链:从当前作用域开始一层层往上找某个变量,直到全局作用域。这种层级关系就是作用域链。
- 变量提升
- 使用 var 关键字声明的变量,会在所有代码执行前被声明(但是 不赋值);
- 使用函数形式创建的函数:
function(){},会在所有代码执行前就被创建,所以可以在函数声明前调用
5、this 指向、new 关键字
5.1 this 指向
- 函数调用,当一个函数不是一个对象的属性时,直接作为函数来调用时,
this指向全局对象 - 方法调用,如果一个函数作为一个对象的方法来调用时,this 指向这个对象
- 构造函数调用,this 指向这个用 new 新创建的对象
5.2 call、apply、bind
- call 接收参数列表
b.call(obj,1,2) - apply 接收参数是数组
a.apply(obj,[1,2]) - bind 返回改变 this 指向的函数
var b = a.bind(obj,1);b(2,3)
5.3 new 实现
- 创建了一个新的空对象
- 链接到原型,将对象的原型设置为函数的 prototype 对象:
obj.__proto__ = Con.prototype - 构造函数的 this 指向这个对象,执行构造函数的代码
- 判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象
function create() {
// 1.创建一个全新的对象
let obj = new Object()
//获取构造函数
let Con = [].shift.call(arguments) //拿到第一个元素
// 2.将对象的__proto__指向构造函数的prototype对象
obj.__proto__ = Con.prototype
//使用新的api obj = Object.setPrototypeOf(obj,Con.prototype);
// 3.绑定this, 以及参数;
let result = Con.apply(obj, arguments)
//4.确保返回的是对象(如果构造器没有返回其他对象,则自动返回这个新对象)
return typeof result === 'object' ? result : obj
}
6、异步
6.1 event loop、宏任务和微任务
6.2 promise、async/await
- promise 使用方法 es6.ruanyifeng.com/#docs/promi…
- promise 参考 juejin.cn/post/684490…
7、事件冒泡、委托
- 冒泡:在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个对象的父级对象传播,最终父级对象触发了事件
- 委托: 把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
8、继承
四、vue
1、简述 MVVM
- Model-View-ViewModel,,Model 层代表数据模型,View 代表 UI 组件,ViewModel 是 View 和 Model 层的桥梁,数据会绑定到 viewModel 层并自动将数据渲染到页面中,视图变化的时候会通知 viewModel 层更新数据。
2、双向绑定原理
当一个 Vue 实例创建时,Vue 会遍历 data 选项的属性,用 Object.defineProperty 将它们转为 getter/setter 并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
3、生命周期理解
-
create 阶段:vue 实例被创建
- beforeCreate: 创建前,此时 data 和 methods 中的数据都还没有初始化
- created:创建完毕,data 中有但未挂载(数据观测、属性和方法的运算、watch/event 时间回调、$el 尚未生成)
-
mount 阶段: vue 实例被挂载到真实 DOM 节点
- beforeMount:可以发起服务端请求,去数据
- mounted: 此时可以操作 Dom
-
update 阶段:当 vue 实例里面的 data 数据变化时,触发组件的重新渲染
- beforeUpdate 数据更新时,被调用,发生在虚拟 Dom 重新渲染和打补丁之前
- updated 由于数据更改导致的虚拟 Dom 重新渲染和打补丁,在这之后调用
-
destroy 阶段:vue 实例被销毁
- beforeDestroy:实例被销毁前,此时可以手动销毁一些方法
- destroyed
-
keep-alive(activated & deactivated)
4、computed 与 watch
-
watch 属性监听 主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销较大的操作时使用
-
computed 计算属性 属性的结果会被缓存,当 computed 中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算,主要当做属性来使用,computed 中的函数必须用 return 返回最终的结果,computed 更高效,优先使用
-
使用场景 computed:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能 watch:当一条数据影响多条数据的时候使用,例:搜索数据
5、v-for 中 key 的作用
key的作用主要是为了更高效的对比虚拟 DOM 中每个节点是否是相同节点;- Vue 在 patch 过程中,通过 key 可以判断两个虚拟节点是否是相同节点,渲染一组列表时,key 往往是唯一标识,所以如果不定义 key 的话,Vue 只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个 patch 过程比较低效,影响性能;
- 从源码中可以知道,Vue 判断两个节点是否相同时主要判断两者的 key 和元素类型等,因此如果不设置 key,它的值就是 undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的 dom 更新操作,明显是不可取的。
6、vue 组件的通信方式
- 父子组件通信
父->子
props,子->父$on、$emit获取父子组件实例 parent、parent、children、 Ref - 兄弟组件通信
Event Bus实现跨组件通信Vue.prototype.$bus = new Vue() Vuex - 跨级组件通信
$attrs、$listeners Provide、inject
7、Vue 的组件 data 为什么必须是一个函数
new Vue是一个单例模式,不会有任何的合并操作,所以根实例不必校验 data 一定是一个函数。组件的 data 必须是一个函数,是为了防止两个组件的数据产生污染。如果都是对象的话,会在合并的时候,指向同一个地址。而如果是函数的时候,合并的时候调用,会产生两个空间。
8、nextTick 的实现
- nextTick 是一个微任务。
- nextTick 中的回调是在下次 Dom 更新循环结束之后执行的延迟回调
- 可以用于获取更新后的 Dom
- Vue 中的数据更新是异步的,使用 nextTick 可以保证用户定义的逻辑在更新之后执行
9、Vue 中的 diff 算法
比较新旧节点,同级比较
10、Vue 的性能优化
- 使用 keep-alive 来缓存组件
- 在更多的情况下,使用 v-if 替代 v-show
- 使用路由懒加载、异步组件
- key 保证唯一
- data 数据层级不要过深,合理的设置响应式数据
11、vue3
五、http
1、http 状态码
1.1 状态码分类
1xx Informational(信息状态码) 接受请求正在处理
2xx Success(成功状态码) 请求正常处理完毕
3xx Redirection(重定向状态码) 需要附加操作已完成请求
4xx Client Error(客户端错误状态码) 服务器无法处理请求
5xx Server Error(服务器错误状态码) 服务器处理请求出错
1.2 常见状态码
200 响应成功
301 永久重定向
302 临时重定向
304 资源缓存
403 服务器禁止访问
404 服务器资源未找到
500 502服务器内部错误
504 服务器繁忙
2、Http 和 Https 区别
HTTP标准端口是 80 ,而HTTPS的标准端口是 443HTTP无法加密,HTTPS对传输的数据进行 SSL 加密在OSI网络模型中,HTTP工作于应用层,而HTTPS的安全传输机制工作在传输层
3、GET 和 POST 区别
1. GET 在浏览器回退不会再次请求,POST 会再次提交请求
2. GET 请求会被浏览器主动缓存,POST 不会,要手动设置
3. GET 请求参数会被完整保留在浏览器历史记录里,POST 中的参数不会
4. GET 请求在 URL 中传送的参数是有长度限制的,而 POST 没有限制
5. GET 参数通过 URL 传递,POST 放在 Request body 中
6. GET 参数暴露在地址栏不安全,POST 放在报文内部更安全
7. GET 一般用于查询信息,POST 一般用于提交某种信息进行某些修改操作
8. GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包
4、http 缓存
-
关于缓存:
- 定义:把不需要重新获取的内容缓存本地
- 使用理由:网络请求相比于 CPU 的计算和页面渲染非常非常慢
- 缓存资源: 静态资源,比如 js css img
-
强制缓存(Cache-Control)
- 由服务器控制,加在响应头(Response Headers)中, 例:
Cache-Control: max-age=3153600
max-age:缓存最大过期时间。 no-cache:可以在客户端存储资源,每次都必须去服务端做新鲜度校验,来决定从服务端获取新的资源(200)还是使用客户端缓存(304)。 no-store:永远都不要在客户端存储资源,永远都去原始服务器去获取资源。 - 由服务器控制,加在响应头(Response Headers)中, 例:
-
协商缓存(对比缓存):服务端判断客户端资源,是否和服务端资源一样, 一致则返回 304,否则返回 200 和最新的资源
- 在 Response Headers 中,有两种。
- Last-Modified:资源的最后修改时间。 对应请求头=>if-Modified-Since
- Etag:资源的唯一标识(一个字符串,类似于人类的指纹) 对应请求头=> if-None-Match
- 在 Response Headers 中,有两种。
-
两者比较
- 优先使用 Etag。
- Last-Modified 只能精确到秒级。
- 如果资源被重复生成,而内容不变,则 Etag 更精确。
-
三种刷新操作对 http 缓存的影响
- 正常操作:地址栏输入 url,跳转链接,前进后退等==>强制缓存有效,协商缓存有效
- 手动刷新:f5,点击刷新按钮,右键菜单刷新==>强制缓存失效,协商缓存有效
- 强制刷新:ctrl + f5,shift+command+r==>强制缓存失效,协商缓存失效
5、从浏览器地址栏输入 url 到请求返回
- 输入 URL 后解析出协议、主机、端口、路径等信息,并构造一个 HTTP 请求
- DNS 域名解析成 IP 地址
- TCP 连接(三次握手)
- 发送 HTTP 请求
- 服务器处理请求并返回 HTTP 报文
- 浏览器解析渲染页面
- 断开连接:TCP 四次挥手
6、跨域
-
解决方案:
- jsonp(利用 script 标签没有跨域限制的漏洞实现。缺点:只支持 GET 请求)
- CORS(设置
Access-Control-Allow-Origin:指定可访问资源的域名) - postMessage(message, targetOrigin, [transfer])(HTML5 新增 API 用于多窗口消息、页面内嵌 iframe 消息传递),通过 onmessage 监听 传递过来的数据
- Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。
- Node 中间件代理
- Nginx 反向代理
7、http 握手、挥手
-
握手
- 第一步:客户端发送 SYN 报文到服务端发起握手,发送完之后客户端处于 SYN_Send 状态
- 第二步:服务端收到 SYN 报文之后回复 SYN 和 ACK 报文给客户端
- 第三步:客户端收到 SYN 和 ACK,向服务端发送一个 ACK 报文,客户端转为 established 状态,此时服务端收到 ACK 报文后也处于 established 状态,此时双方已建立了连接
-
挥手
- 客户端 -- FIN --> 服务端, FIN—WAIT
- 服务端 -- ACK --> 客户端, CLOSE-WAIT
- 服务端 -- ACK,FIN --> 客户端, LAST-ACK
- 客户端 -- ACK --> 服务端,CLOSED
8、安全
8.1 xss 攻击
- XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登陆网站时就会执行这些恶意代码,这些脚本可以读取 cookie,session tokens,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。
- 避免方式:
- url 参数使用 encodeURIComponent 方法转义
- 尽量不是有 InnerHtml 插入 HTML 内容
- 使用特殊符号、标签转义符
cookie设置httpOnly
8.2 CSRF 攻击
- CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
- 避免方式:
- 请求添加 token 校验
- 设置访问白名单,拒绝第三方网站请求
8.3 DDos 攻击
-
DDoS(Distributed Denial of Service)分布式拒绝服务,其原理就是利用大量的请求造成资源过载,导致服务不可用
-
避免方式:
- 限制单 IP 请求频率。
- 防火墙等防护设置禁止 ICMP 包等
- 检查特权端口的开放
9、浏览器存储
9.1 cookie
-
存储大小限制为 4KB
-
数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递
-
只在设置的 cookie 过期时间之前有效,即使窗口关闭或浏览器关闭(默认浏览器关闭失效)
-
作用域:
- 可以是不同的 tab 页;
- 必须同源;
- 要是同一个路径下或者子路径下
9.2 localStorage 和 sessionStorage
- sessionStorage 和 localStorage 不会自动把数据发送给服务器,仅在本地保存
- 存储最大可存 5M
- 数据失效:
- localstorage:数据会永久存储,窗口或浏览器关闭也一直保存,除非代码删除或手动删除
- sessionStorage: 数据只存在于当前会话,浏览器关闭则清空
- 作用域:
- localstorage:
- 可以在同一个浏览器的不同窗口中;
- 可以在不同的 tab 页;
- 必须同源
- sessionStorage:
- 不可以在不同的 tab 页;
- 必须同源;
- 同源且一个标签页包含多个 iframe,可以共享
- localstorage:
http2
- 特性:
- 多路复用
- header 压缩
- 服务端推送静态资源
- 区别:
- 和 1.0 相比,1.1 可以一次传输多个文件
- http1.x 解析基于文本,http2.0 采用二进制格式
六、webpack
- 基础原理问题:juejin.cn/post/684490… juejin.cn/post/694346…
- 热更新原理:Webpack HMR 原理解析
七、模块化
前端模块化详解(完整版)(这里面没有讲 umd) 可能是最详细的 UMD 模块入门指南
八、性能优化
1. 代码层面
- 防抖和节流(resize,scroll,input)
- 减少回流(重排)和重绘
- 事件委托
- css ,js 脚本放 最底部
- 减少 DOM 操作
- 按需加载, webpack 中的 splitChunks
2. 构建层面
- 压缩代码文件,在 webpack 中使用 terser-webpack-plugin 压缩 Javascript 代码;使用 css-minimizer-webpack-plugin 压缩 CSS 代码;使用 html-webpack-plugin 压缩 html 代码。
- 开启 gzip 压缩,webpack 中使用 compression-webpack-plugin ,node 作为服务器也要开启,使用 compression。
- 常用的第三方库使用 CDN 服务,在 webpack 中我们要配置 externals,不打包到最终生成的文件中
3. 其它网络层面
- 使用 http2。因为解析速度快,头部压缩,多路复用,服务器推送静态资源。
- 使用服务端渲染。
- 图片压缩。
- 使用 http 缓存,比如服务端的响应中添加 Cache-Control / Expires 。
九、常用方法
1、防抖
const debounce = function(fn,delay){
let timer = null
return function () {
if(timer){
clearTimeout(timer)
}
timer=setTimeout(()=>{
fn()
},delay)
}
}
...
//触发事件
const handleDebounce = debounce(()=>{
console.log('被触发了!')
},800)
=====> handleDebounce()
2、节流
const throttle = function (fn, delay) {
let flag = true
return function () {
if (!flag) return;
flag = false;
fn();
setTimeout(() => {
flag = true;
}, delay)
}
}
...
//触发事件
const handleThrottle = throttle(() =>{
console.log('被触发了!')
}, 800)
====> handleThrottle()
3、去重
//数组
// 1. set
const arr = [2, 7, 5, 7, 2, 8, 9]
console.log([...new Set(arr)]) // [2,7,5,8,9];
// 2. filter
function unique(arr) {
return arr.filter((item, index, array) => {
return array.indexOf(item) === index
})
}
//对象
const list = [
{ age: 18, name: '张三' },
{ age: 18, name: '李四' },
{ age: 18, name: '王五' },
]
let hash = {}
const newArr = arr.reduce((item, next) => {
hash[next.age] ? '' : (hash[next.age] = true && item.push(next))
return item
}, [])
console.log(list)
4、数组扁平化
function flatten(arr) {
return arr.reduce((result, item) => {
return result.concat(Array.isArray(item) ? flatten(item) : item)
}, [])
}
function flat(arr, depth = 1) {
if (depth > 0) {
// 以下代码还可以简化,不过为了可读性,还是....
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flat(cur, depth - 1) : cur)
}, [])
}
return arr.slice()
}
5、深浅拷贝
- 浅拷贝(修改原来对象 a,复制值 b 改变)
1. Object.assign(target,source)
2. es6对象扩展运算符。
-
深拷贝(修改原值,复制值不改变)
let b =JSON.parse(JSON.stringify(obj))lodash.defaultsDeep(object, [sources])- 手写:
// function deepClone(obj) { if (!obj || typeof obj !== 'object') return let newObj = Array.isArray(obj) ? [] : {} for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key] } } return newObj }
6、排序
十、vite 相关
十一、其它
-
Array
- 判断数组
//1.instanceof var a = [] console.log(a instanceof Array) //返回true //2.constructor console.log([].constructor == Array) //3.Object.toString const a = [] Object.prototype.toString.call(a) //"[object Array]" //4.isArray const a = [] const b = {} Array.isArray(a) //true Array.isArray(b) //false- 数组扁平化:
falt - 数组去重:
set - 类数组=>数组:
Array.from - 数组包含某个元素:
//includes ;[1, 2, 3].includes(2) //true //indexOf var fruits = ['Banana', 'Orange', 'Apple', 'Mango'] var a = fruits.indexOf('Apple') // 2 无返回-1 //find() const arr = [1, 5, 10, 15] arr.find((value, index, arr) => { return value > 9 }) //10 无返回undefined- 生成数组[1,1,1...,1]:
new Array(100).fill(1)、 Array.from({ length: 100 }, x => 1)
结尾
如果对你有帮助,点个赞❤再走呗!有错误的话还请指正