| 断点 | 最小宽度 | 常见设备举例 |
|---|
| sm | 640px | 大屏手机(iPhone Plus)、小平板 |
| md | 768px | 平板(iPad mini、iPad 竖屏) |
| lg | 1024px | 平板横屏、较小的笔记本 |
| xl | 1280px | 普通笔记本、桌面显示器 |
| 2xl | 1536px | 大屏桌面显示器、超宽显示器 |
<640px:一般为手机sm:大手机/小平板md:平板lg:大平板/小笔记本xl:主流笔记本/桌面2xl:大桌面、超宽屏- 这些断点可以根据项目需求自定义
- 绘画的 canvas 元素
- 原生多媒体支持( video 和 audio )
- 支持 SVG(基于 XML 的矢量图形,放大后不失真,适合图标、地图等场)
- 语义化标签 :header、main、footer、aside、nav、section、article
- 拖放属性 :
- 增强型表单,新增多种输入类型和属性
- 新输入类型:email(邮箱验证)、tel(电话格式)、number(数字输入)、date(日期选择器)、range(滑块)等。
- 新属性:required(必填项)、placeholder(提示文本)、autocomplete(自动补全)、pattern(正则验证)等。
- 本地存储(localStorage、sessionStorage)
- WebSocket API:提供全双工通信通道,允许客户端与服务器建立持久连接,实现实时数据交互(如聊天、实时通知),替代传统的轮询(Polling)方式,效率更高
- 选择器:伪类选择器 、 属性选择器
- 圆角 border-radius
- 透明度 opacity、rgba
- 盒阴影 box-shadow
- 弹性盒 display:flex
- 盒模型 box-sizing (border 和 padding) 不会计算 在宽高中
- 过渡
- 渐变
- 透明度
- 媒体查询
块级格式化上下文
BFC是一块独立的渲染区域,可以将BFC看成是元素的一种属性,拥有了这种属性的元素就会使他的子元素与世隔绝,不会影响到外部其他元素
·设置浮动 float,不包括none
·设置定位(绝对定位或固定定位),absoulte 或者 fixed
·行内块显示模式,inline-block
·设置 overflow,即 hidden,auto,scroll
·表格单元格,table-cell
·弹性布局,flex
特性:
- 同一个 BFC 下外边距会发生折叠
- BFC 可以阻止元素被浮动元素覆盖
- BFC 可以清除浮动
回流:页面中元素的尺寸,布局,隐藏等改变而需要重新构建页面
- 第一次渲染页面(内容和文字等都发生改变)。
- 浏览器窗口尺寸的改变。
- 页面元素(图片,文字)位置和大小尺寸的改变。
- 新增和删除可见元素。
- 一些style属性发生变化导致元素变化:(如边框,下划线,css伪类)
重绘:页面中元素属性发生改变,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color,则就叫称为重绘
区别:
回流必将引起重绘,而重绘不一定会引起回流。
- 只有颜色改变的时候就只会发生重绘而不会引起回流
- 当页面布局和几何属性改变时就需要回流
- 添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
如何避免和减少回流和重绘
- 减少dom和样式的修改,不多次修改样式
- 样式集中,尽量使用外部样式表和外部js,读写分离,这样有利于服务器和浏览器缓存
- 能使用css的就不用js操作样式:(每次js操作都会导致重绘或者回流)
- 页面中多次需要重排的元素,position使用 absolute 或 fixed
- 尽量不使用表格布局(无定宽高的表格宽高由最后一行决定,绘制到最后一行不合理的时候会反复进行计算回流)
width: 100px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
- Flex布局,任何元素(块级 / 行内),父元素高度已知或未知均可
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 300px; /* 父元素需有高度(可固定/百分比/由内容撑开) */
}
.child {
width: 100px;
height: 100px;
}
- Grid 布局(适合二维布局场景),父元素定义为网格容器,子元素需居中
/* 父元素样式 */
.parent {
display: grid;
place-items: center; /* 同时设置水平和垂直居中(等价于 align-items: center + justify-items: center) */
height: 300px;
}
/* 子元素无需额外样式 */
.child {
width: 100px;
height: 100px;
}
- 基于Position定位(传统方法,兼容旧浏览器)-已知子元素尺寸(固定宽高)
.parent {
position: relative;
height: 300px;
}
.child {
position: absolute;
top: 50%; /* 父元素垂直方向中点 */
left: 50%; /* 父元素水平方向中点 */
width: 100px;
height: 100px;
margin-top: -50px; /* 自身高度的一半(向上偏移) */
margin-left: -50px; /* 自身宽度的一半(向左偏移) */
}
.parent {
height: 100px;
text-align: center; /* 水平居中 */
line-height: 100px; /* 垂直居中(值等于父元素高度) */
}
/* 子元素为文本或行内元素 */
.child {
display: inline; /* 确保是行内元素 */
}
- 未知子元素尺寸:绝对定位 + transform: translate(基于自身尺寸偏移)
.parent {
position: relative;
height: 300px;
}
.child {
position: absolute;
top: 50%;
left: 50%;
/* 向左/上偏移自身尺寸的 50%,无需知道宽高 */
transform: translate(-50%, -50%);
}
- 绝对定位 :设置绝对定位,上下左右为0,margin为auto
.parent {
position: relative;
height: 300px;
}
.child {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* 水平垂直均居中 */
margin: auto;
/* 可固定或自适应 */
width: 100px;
height: 100px;
}
- display : none
- visibility : hidden
- opacity : 0
- position : 利用定位将元素的top和left值设为足够大的负数,使它移出屏幕在屏幕上看不见
- overflow : hidden
- z-index: 负值
- transform: scale(0,0):将元素缩放为 0
- height、width 为 0
- display:none , 元素会被隐藏,不会占空间
- visibility:hidden,元素会被隐藏,但还是会占空间
可以继承:
字体相关 - font-size、font-family、font-weight
文本相关 - color、line-height、text-align
其他 - visibility、cursor
无法继承:宽、高、padding、margin、border、background、定位
relative :相对定位,相对于其原来的位置进行定位
absolute :相对于没有定位以外的一个祖先元素进行定位,脱离文档流
fixed :固定定位 ,相对于屏幕视⼝(viewport)的位置来指定元素位置,脱离文档流
sticky :粘性定位,相对于最近的滚动祖先容器
当多个定位元素重叠时,可以使用 z-index属性控制它们的堆叠顺序。数值越大,元素越靠近用户。需要注意的是,z-index只对 position值不为 static的元素生效
缩放
transform: scale(0.5,0.5);
设置元素为浮动后,display 的值是 block
px:绝对单位,页面按精确像素展示
em:相对单位,如果自身定义了 font-size 按自身来计算,如果自身没有,则以最近父节点字体的大小,整个页面内1em 不是一个固定的值
rem:相对单位,可理解为root em, 相对根节点 html 的字体大小来计算
vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
- 设置元素为浮动后,display 的值是 block
- 有权访问另一个函数作用域中的变量的函数
- 特点
- 函数嵌套函数
- 函数内部可以引用函数外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
- 优点: 避免全局污染 ,保护私有变量 ,延长了变量的生命周期
- 缺点: 处理不当,容易造成内存泄漏
- 应用:防抖
- JS的垃圾回收机制是为了以防内存泄漏
- JS有两种变量,全局变量和在函数中产生的局部变量。局部变量的生命周期在函数执行过后就结束了,此时便可将它引用的内存释放(即垃圾回收),但全局变量生命周期会持续到浏览器关闭页面
- 现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除(mark and sweep)、引用计数(reference counting)
| break | 用于跳出循环 |
|---|
| continue | 跳过循环中的一个迭代 |
| do ... while | 执行一个语句块,在条件语句为 true 时继续执行该语句块 |
| for | 在条件语句为 true 时,可以将代码块执行指定的次数 |
| for ... in | 用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作) |
| function | 定义一个函数 |
| if ... else | 用于基于不同的条件来执行不同的动作 |
| return | 返回结果,并退出函数 |
| switch | 用于基于不同的条件来执行不同的动作 |
| throw | 抛出(生成)错误 |
| try | 实现错误处理,与 catch 一同使用 |
| catch | 语句块,在 try 语句块执行出错时执行 catch 语句块 |
| var | 声明一个变量 |
| while | 当条件语句为 true 时,执行语句块 |
- JavaScript 变量生命周期在它声明时初始化
- 局部变量在函数执行完毕后销毁
- 全局变量在页面关闭后销毁
- 基本数据类型:数据存储在栈内存中
- 引用数据类型:数据存放在堆内存中,栈中存放了一个引用地址,指向堆内存中的数据
浅拷贝是复制,两个对象指向同一个地址
深拷贝是新开栈,两个对象指向不同的地址
浅拷贝:只拷贝对象的引用、而不深层次的拷贝对象的值,引用指向的是同一个对象,多个对象指向 堆内存 中的同一对象,任何一个修改都会使得所有对象的值修改,因为它们公用一条数据
Object.assign 第一层是深拷贝,第二层是浅拷贝
concat()
slice()
深拷贝:将引用类型的值全部拷贝一份,形成一个新的引用类型,在堆内存中重新开辟一个空间,数据发生变化,不会修改原数据
拷贝的是他们的引用地址,数据发生变化,不会修改原数据
Object.assign() 这种方式第一层是深拷贝,第二层是浅拷贝
ES6扩展运算符
JSON.parse(JSON.stringify(obj1)); 但是这种方式存在弊端,会忽略undefined、symbol和函数
函数库 lodash 的_.cloneDeep方法
递归拷贝
| 方法 | 作用 |
|---|
| split() | 把字符串分割为子字符串数组 |
| slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分。 |
| charAt() | 返回指定索引位置的字符 |
| concat() | 连接两个或多个字符串,返回连接后的字符串 |
| indexOf() | 返回字符串中检索指定字符第一次出现的位置 |
| match() | 找到一个或多个正则表达式的匹配 |
| replace() | 替换与正则表达式匹配的子串 |
| trim() | 移除字符串首尾空白 |
| toString() | 返回字符串对象值 |
- split() 把字符串分割为子字符串数组
- slice() 提取字符串的片断,并在新的字符串中返回被提取的部分
- charAt() 返回指定索引位置的字符
- concat() 连接两个或多个字符串,返回连接后的字符串
- indexOf() 返回字符串中检索指定字符第一次出现的位置
- match() 找到一个或多个正则表达式的匹配
- replace() 替换与正则表达式匹配的子串
- trim() 移除字符串首尾空白
- toString() 返回字符串对象值
- toUpperCase() 把字符串转换为大写
| 分类 | 核心方法 | 关键点 |
|---|
| 增删改查 | push(), pop(), shift(), unshift(), splice(), slice() | 直接修改原数组 vs 返回新数组 |
| 遍历 | forEach(), map(), filter(), reduce(), find(), some(), every() | 回调函数参数(item, index, array) |
| 转换/拼接 | join(), concat(), flat(), flatMap() | 多维数组扁平化、链式操作 |
| 排序/搜索 | sort(), reverse(), indexOf(), includes(), findIndex() | sort() 默认按字符串排序的陷阱 |
| 分类 | 核心方法/操作 | 关键点 |
|---|
| 属性操作 | Object.keys(), Object.values(), Object.entries(), delete | 遍历对象的键、值、键值对 |
| 合并/克隆 | Object.assign(), 展开运算符 {...obj}, JSON.parse(JSON.stringify()) | 浅拷贝 vs 深拷贝 |
| 冻结/保护 | Object.freeze(), Object.seal() | 对象不可变性的控制 |
| 原型链 | hasOwnProperty(), Object.create() | 避免原型链污染的安全 |
| 分类 | 核心方法 | 关键点 |
|---|
| 截取/分割 | slice(), substring(), split(), substr()(已废弃) | slice 支持负数索引,substring 自动排序参数 |
| 搜索/替换 | indexOf(), includes(), replace(), replaceAll() | 正则表达式的高级替换 |
| 格式化 | toUpperCase(), toLowerCase(), trim(), padStart(), padEnd() | 空格处理、字符串对齐 |
| 模板字符串 | Hello ${name} | 多行字符串、表达式嵌入 |
| 方法 | 适用场景 | 特点 |
|---|
| for | 精确控制循环次数、索引操作 | 灵活但代码冗余 |
| for...of | 遍历可迭代对象(数组、字符串、Map、Set) | 直接获取元素值 |
| forEach() | 数组遍历(不需要中断或返回值) | 无法 break 或 return |
| map() | 数组转换(返回新数组) | 必须处理返回值 |
| while/do...while | 不确定循环次数时(如读取流数据) | 前置条件 vs 后置条件检查 |
- 原型:函数的
prototype 属性,每个函数都有一个 prototype 属性,指向生成该函数的原型对象 - 原型链:每个对象都有一个 proto 属性,指向生成该对象的原型对象(这样我们就找到了是哪个对象生成了该对象)
- 原型链一般用于继承,原型链的核心就是依赖对象的 proto 的指向,当自身不存在属性时,就一层层往上找,直到找到 Object.prototype
因为 proto 实质找的是 prototype ,所以我们只要找这个链条上的构造函数的原型(prototype)
1.原型链继承 :继承父类构造函数原型上的属性和方法
3.借用构造函数继承
3.组合继承: 原型链继承 和 借用构造函数继承
4.ES6继承方法 :
extends
super关键字,它指向父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错
- 全局作用域下,指向 window
- 函数作用域下
- 非严格模式:指向 window
- 严格模式下,为 undefined
- 对象中,指向当前该对象
- 普通函数调用 :指向 window
- 构造函数调用 :指向 实例对象
- 事件绑定的方法:指向 事件的对象
- 箭头函数 :箭头函数中没有 this,this 指向就是定义时所在的作用域中的 this 的值
- apply,call,bind 改变函数运行时的指向,当第一个参数为null或undefind时,指向 window
- apply,call 临时改变this指向一次
- apply : 可以传入数组,第一个参数:要绑定给this的值 第二个参数:参数列表(可以是数组),使用apply方法改变 this 指向后原函数会立即执行,且此方法只是临时改变thi指向一次。
- call : 传入参数列表,改变函数指向并立即调用,第一个参数要:绑定给this的值,第二个参数必须是单个参数列表,以逗号分隔的方式,不能是数组
- bind :不会调用函数,可以改变函数内部指向,返回绑定this之后的函数
- bind 方法和 call 很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。
- 这三个方法的主要区别在于如何传递参数和何时执行函数
apply 和 call 立即执行函数,而 bind 则返回一个新的函数,可以在之后的任何时间调用。
- 三者都可以改变函数的this对象指向
- 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为 undefined 或 null,则默认指向全局window。
- 三者都可以传参,但是apply是数组,而 call、bind 是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
- bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行
在可视区域之外的图片默认不加载,随着页面的滚动,图片进入了可视区域的范围,则触发图片的加载显示
在图片没有进入可视区域时,先不给<img>的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。
img 的 src 属性 ,初始化img 的时候,src不能是真实的图片地址,把真实地址存放在一个自定义属性中,例如 data-src 来存放
- undefined
- 声明一个变量,但是没有赋值
- 访问对象上不存在的属性或者未定义的变量
- 函数定义了形参,但没有传递实参
- 使用 void 对表达式求值
- null
- 如果定义的变量在将来用于保存对象,那么最好将该变量初始化为null,而不是其他值
- 当一个数据不再需要使用时,我们最好通过将其值设置为null来释放其引用,这个做法叫做解除引用
- 可以把 undefined 看作是空的变量,而 null 看作是空的对象
- == 只比较它们的值是否相等(会进行隐式转换)
- === 会比较它们的值和数据类型是否相等
- || 适用于任何假值的情况,包括 null, undefined, false, 0, NaN, 空字符串 ''
- ?? 仅适用于 null 和 undefined 的情况
- 相邻的数据进行两两比较,小数放在前面,大数放在后面,这样一趟下来,最小的数就被排在了第一位,第二趟也是如此,如此类推,直到所有的数据排序完成
- let、const
- 结构赋值
- 扩展运算符
- 箭头函数
- Promise
- Set :不会出现重复的值
- Map :键值对形式
- async await
- class类
- ES6模块化
- 装饰器
- var 声明的变量,没有“块级作用域”的限制
- let / const 声明的变量,具有“块级作用域”
- var 声明的变量存在“变量提升”,let / const没有
- let / const 有暂时性死区 ,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是 在声明之前就使用这些变量,就会报错
- let / const 不允许重复声明
- let 和 const 的区别 :const 声明的是常量,不能被修改
- 如果解构不成功,变量的值就等于 undefined
- 解构赋初始值时,如果解构成功,则默认值失效,赋初始值时,严格等于 undefined ,才能赋初始值
- 数组解构赋值
let [a, b, c, d, e, f] = arr
- 对象解构赋值
- 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let obj = {
a: 1,
b: [1, 2, 3],
c: false,
d: { name: 'geekxia', age: 10 },
}
let { a, b, c, d, e } = obj
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
1.交换变量的值
let a = "hello";
let b = "world";
[a, b] = [b, a];
2.从函数返回多个值,函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便
3.函数参数的定义,解构赋值可以方便地将一组参数与变量名对应起来
4.提取JSON数据数据,解构赋值对提取JSON对象中的数据,尤其有用
5.函数参数的默认值
6.遍历Map结构
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) { console.log(key + " is " + value); }
- Promise 是异步编程的一种解决方案,是一个对象
- Promise 有三种状态:pending (进行中) 、fulfilled (成功)、reject(失败)
- 状态改变只有两种可能:pending(进行中) => fulfilled (成功) / pending(进行中) => reject(失败)
- Promise对象是一个构造函数,用来生成 Promise 实例,接收一个函数作为参数,函数中有两个参数(resole,reject),resole表示成功的回调,reject表示失败的回调,可以在回调后面调用 then()、cath()、finally( )
- then()方法表示成功时的回调
- cath()方法表示失败时的回调
- finally()方法表示成功或失败都会执行的回调
- repeat() 返回一个新字符串,表示将原字符串重复 n 次
- 参数如果是小数,会被取整
- 如果 repeat 的参数是负数或者 Infinity ,会报错
- 如果参数是0到-1之间的小数,则等同于0
- 参数 NaN 等同于0
- 如果 repeat 的参数是字符串,则会先转换成数字
- async 用来修饰函数,将函数的返回值封装成 Promise 对象
- await 后面跟一个 Promise 对象(如果不是会转换成 Promise 对象),表达式返回 Promise 结果
- 浏览器回退的时候,GET请求不会重新请求,而 POST 请求会重新请求
- GET请求会缓存,而 POST 不会
- GET参数会暴露在地址栏上,相对不安全,而 POST 不会,相对安全
- 存储大小的区别
- cookie数据大小不能大于4K
- localStorage 和 sessionStorage则可以达到5M
- 时效性
- cookie在设置的有效期内一直有效
- localStorage存储持久数据,只要不手动清除则一直存在
- sessionStorage数据在当前浏览器关闭后就会被自动清除
- 数据与服务器间的交互方式
- cookie的数据会自动传递到服务器端,服务器端也可以写cookie到客户端
- localStorage和sessionStorage不会把数据自动传到服务器端,仅在本地存储
- 200 成功
- 300 重定向
- 301 永久重定向(请求资源的URL被永久的改变,新的URL会在响应的Location中给出)
- 302 临时重定向
- 304 未修改(协商缓存生效)。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
- 307 临时重定向。与302类似。使用GET请求重定向
- 400 客户端请求有语法错误,不能被服务器所理解
- 401 请求未经授权
- 403 服务器收到请求,但是拒绝提供服务
- 404 请求资源不存在,举个例子:输入了错误的URL。
- 405 方法不被允许
- 500 服务器发生不可预期的错误
- 503 服务器当前不能处理客户端的请求,一段时间后可能恢复正常
- 504 网关超时
事件循环是 js实现异步的一种方法,也是 js的执行机制,由调用栈、任务队列(宏任务和微任务)以及渲染步骤组成
JS是单线程的,浏览器在执行JS代码时先执行同步任务,再执行异步任务
**主线程任务——>微任务(promise)——>宏任务(setTimeout)——>宏任务里的微任务——>宏任务里的微任务中的宏任务——>直到任务全部完成**
调用栈(Call Stack)
用于存储同步任务的执行上下文(函数调用栈)
LIFO(后进先出)结构,代码按顺序执行
任务队列(Task Queue)
宏任务队列(Macrotask Queue):setTimeout、setInterval、DOM 事件回调、I/O 操作等
微任务队列(Microtask Queue):Promise.then、MutationObserver、queueMicrotask
渲染引擎(Render Pipeline)
负责页面渲染(样式计算、布局、绘制)
与事件循环协作,在适当时机更新界面
异步任务包括 宏任务 、 微任务
**宏任务**:
setTimeout
setInterval
主线程任务完成、所有微任务也完成的情况下就会立即执行
**微任务:**
promise
process.nextTick(node 独有)
- HTTP超文本传输协议,主要作用就是规定浏览器与服务器之间如何通信以及请求响应数据包的格式
- 三次握手(建立连接的一个过程)
- 第一次:浏览器首先发送SYN码给服务器,请求和服务器建立连接
- 第二次:服务器接收到SYN码后,发送SYN+ACK码给浏览器,告诉浏览器已建立连接
- 第三次:浏览器接收ACK码,验证是否正确,若正确就建立数据连接,可以进行数据传输
- 需要三次握手才能确认双方的接收与发送能力是否正常
- 四次挥手(断开连接的过程)
- 第一次:浏览器发送FIN码给服务器,告诉服务器,数据传输完成
- 第二次:服务器接收到FIN码,然后发送ACK码给浏览器,告诉浏览器,你可以断开连接
- 第三次:服务器,继续发送FIN + ACK码,告诉浏览器我的数据发送完毕
- 第四次:浏览器接收到FIN码 + ACK码后,同样会发送ACK码给服务器,告诉服务器,我已接收到,你可以断开连接
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的 ssl 加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
- 就是在触发事件后,在 n 秒内(特定时间内),函数只执行一次,如果在 n 秒内(特定时间内),又触发了事件,则会重新计算函数执行的时间
- 防抖函数分为非立即执行版和立即执行版
- 核心是利用 setTimeout和 clearTimeout
- 非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- search远程搜索框:防止用户不断输入过程中,不断请求资源,n秒内只发送1次,用防抖来节约资源
- 按钮提交场景,比如点赞,表单提交等,防止多次提交
- 监听 resize 触发时,调整浏览器窗口大小会不断触发 resize ,使用防抖可以让其只执行一次
- 滚动事件
节流,就是指连续触发事件,但是在 n 秒 内只执行一次函数
- 拖拽场景:固定时间内只执行一次, 防止高频率的的触发位置变动
- 监听滚动事件:实现触底加载更多功能
- 屏幕尺寸变化时, 页面内容随之变动,执行相应的逻辑
- 创建一个全新的对象
- 这个对象的 proto 属性 要指向 构造函数 的 原型 prototype
- 执行构造函数,使用 call/apply 改变 this 的指向
- 返回值为object类型则作为new方法的返回值返回,否则返回上述全新对象。
(1)创建一个新对象
(2)将对象的proto属性指向构造函数的 prototype 属性
(3)将构造函数的作用域赋给新对象(因此this就指向了这个对象)
(4)返回新对象
- DNS 解析:将域名解析成 IP 地址
- 生成 HTTP 请求报文
- TCP 连接:TCP 三次握手;(三次握手的目的:为了防止已经失效的连接请求报文段突然又传送到了服务器端,从而产生错误)
- 发送 HTTP 请求;
- 服务器处理请求并返回 HTTP 报文;
- 浏览器解析渲染页面;
- 断开连接:TCP 四次挥手。
- 原因
- js 执行过程中的错误
- 资源错误
- 网络延迟,JS加载延迟 ,会阻塞页面
- 预防
- 跨站点请求伪造 ,攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求
- 预防
- token验证
- 由于恶意用户无法窃取cookie,只能利用用户cookie模拟未携带token的http请求,那只要在服务器端进行token验证就可以防御xsrf的攻击。比如我们可以将token存储在localStorage中
- 验证码
- 需要用户自己来填写验证码从而识别是否是用户主动发起的该请求
- 优点:简单粗暴、低成本
- 缺点:用户体验不好,需要多次验证
- Referer 字段
- 利用 HTTP 头中的 Referer 判断请求来源是否合法,Referer记录了该 HTTP 请求的来源地址
- 跨站脚本攻击,代码注入攻击,注入恶意脚本,利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全
- 预防
- 输入过滤
- 对用户的输入进行过滤,包括text、post等等所有输入进行可靠性检测。
- 也可以制作一个白名单,一但输入中的字符不在白名单内,自动过滤掉。
- 转义
- 与正则的思想类似,对比如<、>等等特殊字符进行转义处理。
- 验证码
- 服务端渲染开启模板引擎自带的 HTML 转义功能
- 主动检测和发现,可使用 XSS 攻击字符串和自动扫描工具寻找潜在的 XSS 漏洞
- 扩展运算符结合 set 集合 ...new Set(xxx)
- 利用 双重for循环,结合 splice 方法
- 利用 filter() 或 filter() + indexOf 去重
- 利用 for 循环 搭配 indexOf 去重
- 利用 for 循环结合 includes 实现数组去重
1.使用 lodash 库的 omit 方法:
安装 lodash 库并使用 omit 方法来去除不需要的字段。
这种方法简洁且易于维护,适用于需要处理多个字段的情况。
const userData = omit(userInfo, ['confirmPassword', 'captcha']);
2.使用 Object.keys 和 reduce:
通过 Object.keys 获取对象的所有键,然后使用 reduce 方法构建一个新的对象,排除不需要的字段。
这种方法灵活且可控,适用于复杂的字段管理。
const userData = Object.keys(userInfo).reduce((acc, key) => {
if (key !== 'confirmPassword' && key !== 'captcha') {
acc[key] = userInfo[key];
}
return acc;
}, {} as Partial<UserDto>);
3.使用 for...in 循环:
通过 for...in 循环遍历对象的所有属性,并构建一个新的对象,排除不需要的字段。
这种方法直观且易于理解,适用于简单的字段管理。
const userData: Partial<UserDto> = {};
for (const key in userInfo) {
if (key !== 'confirmPassword' && key !== 'captcha') {
userData[key] = userInfo[key];
}
}
4.使用 Object.assign 和 delete:
通过 Object.assign 创建一个新的对象,然后使用 delete 删除不需要的字段。
这种方法简单直接,适用于需要删除
const userData = Object.assign({}, userInfo);
delete userData.confirmPassword;
delete userData.captcha;
- forEach 循环过程中不可以中断
- for 循环可以使用 关键字 break、return、continue 进行中断
- return 关键字并不是专门用于跳出循环的,return 的功能是结束一个方法。
- continue 只是中止当前循环,接着开始下一次循环。
- break 立即终止当前所在的循环或 switch 语句,并跳出循环体,会继续执行该循环之后的代码(如果有的话)
| 关键字 | 终止范围 | 适用场景 | 返回值 |
|---|
break | 当前循环或 switch | 循环、switch | 无 |
continue | 当前循环迭代 | 循环 | 无 |
return | 当前函数 | 函数内部 | 有(可指定) |
for in 适合遍历对象的属性,for of 适合遍历数组for in 循环出的是 key 值,for of 循环出的是 valuefor in 可以遍历可枚举属性,for of 遍历的是可迭代的for of 不能直接遍历对象,需要配合 Object.keys() 搭配使用
- 强制缓存:不会向服务器发送请求,直接命中内存中的缓存资源,从chrome Network中可以看到资源200且from disk cache或from memory cache。
- 强制缓存 就是不会向服务器发送请求,而是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程
- 协商缓存:向服务器发送请求,服务器根据request header内的参数来判断是否需要更新此资源,如果不需要更新,服务器返回304的状态码,然后通知浏览器读取本地缓存。
- 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
- 总结:强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用强缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,使用则返回304,继续使用协商缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;
- React16.8 和 Vue3.0
- 函数式编程使得代码单元相比面向对象来说更加独立,在tree shaking(移除 JavaScript 上下文中的未引用代码(dead-code))过程中更便于打包工具对未使用的代码进行过滤,对项目体积有一定的优化
- 函数式编程以函数为代码单元,相比于面向对象的方式减少了对this的控制,对于js这种this指向可能会发生改变的语言,一定程度上减轻了开发人员对于this指向问题的困扰
- 函数式有利于单元测试
- 集合结构:该结构的数据元素间的关系是“属于同一个集合”
- 线性结构:该结构的数据元素之间存在着一对一的关系
- 树型结构:该结构的数据元素之间存在着一对多的关系
- 图形结构:该结构的数据元素之间存在着多对多的关系,也称网状结构