目录
22 try-catch-finally处理异常 保证代码可以运行 22
3.6.4 当接口文档中有请求参数时【以get请求为例】 31
3.7 axios-基地址【在调用axios之前设置】 31
7.1 如何阻止默认表单的行为【目的:避免form提交数据】 36
7.2 利用插件快速获取表单数据【display:none的表单元素也会拿到数据】 36
7.3 FormData和file类型表单和axios的应用 37
11.2.2 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。 42
第一章
1 作用域
组成 | 描述 |
局部作用域【函数作用域,块级作用域】 | 局部作用域声明的变量外部不可用访问 在JavaScript中使用{}包裹的代码称为“代码块”,代码块内部声明的变量外部有可能无法被访问。【块级作用域,包括if块级作用域,for循环的块级作用域,{}里面包裹的代码块】 在函数内部声明的变量只能在函数内部访问,外部无法直接访问 函数内部声明的变量可以称为局部变量 |
全局作用域 | script标签和.js文件的最外层就是全局作用域,在此声明的变量在函数内部可以被访问 在全局作用域声明的变量叫做-全局变量 省略关键字(let/const)声明的变量等同于window添加属性,也是全局【不推荐:易导致全局变量污染】 |
2 作用域链
概念 | 使用变量时,如果在当前作用域没有,会一层一层的向上找,找到全局作用域为止,这种一层一层的关系,就是作用域链 |
3 闭包
闭包是一个函数以及其捆绑的周边环境状态的组合
简而言之:函数以及它内部能够访问变量的组合->闭包
使用闭包可以对外提供有限的访问权限
作用 | 描述 |
提供-输出权限 | 保护局部变量,提供打印功能【内部函数可以访问外部函数变量,在内部函数可以打印输出该变量值】 |
提供-修改权限 | 保护局部变量,提供修改的方法【通过return返回的函数,该函数可以通过形参的形式改变外部函数变量的值,但该值只会在内部函数的内部生效,并不会污染外部函数的变量值】 |
保护局部变量,提供了累加的方法 |
4 变量提升
概念:使用var关键字声明的变量,在预解析阶段会将变量的声明提升到当前作用域的顶级
5 函数提升
函数在声明之前即可使用
注意:在开发中不推荐
4 动态参数arguments
概念:函数内部都可以获取参数的 局部变量 – 伪装数组【forEach、map方法都用不了】【函数内部可以直接使用的变量】
伪数组:
特点 |
有length属性 |
索引从0开始 |
querySelectorAll |
5 剩余参数
剩余参数只能写在最后一个位置
剩余参数允许开发者以“真数组“的形式接收不定数量的参数
使用位置 | 描述 |
函数形参 | //[]表示可以省略的意思,自定义参数名用于接收函数调用的所有//实参 function 函数名([参数列表],…自定义参数名) |
只能写在最后一个位置。得到的是除了已有参数的剩余参数。 | |
数组解构 | //会将目标数组名中的数据保存到对应索引的变量中,剩余的数组数据 用数组保存到parm变量中 [变量1名,变量2名,…parm]=目标数组名 |
对象解构 | //会将目标对象名的属性名和左边的变量名进行值的匹配,匹配上就将该属性对应的属性值赋值给左边的变量。parm为目标对象中的其他未匹配的属性和方法组成的对象 {变量1名,变量2名,…parm }=目标对象名 |
5.1 剩余参数和arguments的区别
剩余参数,获取的是没有实参的参数,arguments可以获取所有参数
剩余参数是真数组,arguments是伪数组
6 箭头函数
箭头函数表达式的语法比函数表达式更简洁
箭头函数表达式适用于那些需要匿名函数的地方
6.1 语法:
function替换为=>
什么时候可以省略小括号:一个参数【或者剩余参数】
什么时候可以省略{}:当只有一个return语句【函数体只有一行,需要去掉{}以及{}内的return关键字】【只有一行语句体可以去掉{},return也必须去掉】
arguments不可用
6.2 箭头函数-this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。
局部,块级,全局,作用域链
dom元素绑定事件时,还是建议使用function完整的写法,不要使用箭头函数,因为箭头函数this的指向不再是事件源【触发事件的dom元素】,而是自己作用域的上一级作用域中的this指向。
箭头函数中的this继承于上一个作用域中的this
7 对象相关
对象属性值为目标变量时,目标变量名和属性名同名,可以省略属性值这个目标变量名。【这里person为我们定义的对象】【方法简写:省略function关键字】
7.1 对象简写【ES6简写】
以前写法 | 简写 |
//变量名和下面的属性一样时 let 目标变量名=变量值 const person={ 属性名:目标变量名 } | //变量名和下面的属性一样时 let 变量名=变量值 const person{ 属性名 } |
//对象中的方法 const person={ 目标方法名:function(){ //方法体 } } | //对象中的方法简写 const person={ 目标方法名(){ //方法体 } } |
7.2 对象扩展运算符【对象解构:同时剥去最外层的{},将左边{}中的变量和右边对象{}中的属性进行匹配,匹配上就将该属性对应的属性值赋值给该变量,没匹配上就返回undefined】【这里扩展运算符用红色三个点加粗表示】
语法 | 描述 |
const 目标变量名 = { 属性: “属性值” } const 自定义变量名 = { …目标变量名, 其他属性, } | 会将目标变量名保存的这个对象的所有属性和方法放到自定义变量名保存的这个对象中去作为自定义变量名保存的对象的属性和方法,其他属性和方法可以和目标变量名对象保存的属性和方法重复,在自定义变量名对象中,后写的属性会覆盖前面的属性。 |
const {变量1名,变量2名,…}=对象名 | 会将左边的变量名列表中的变量名去和右边对象中的属性名进行值的匹配,匹配上就将右边对象对应的属性的属性值直接赋值给左边的变量。以后该作用域中就可以直接使用该变量名来获取对象中对应的属性的属性值了。 |
const {变量1名,变量2名=默认值,…}=对象名 | 会将左边的变量名列表中的变量名去和右边对象中的属性名进行值的匹配,匹配上就将右边对象对应的属性的属性值直接赋值给左边的变量。以后该作用域中就可以直接使用该变量名来获取对象中对应的属性的属性值了。如果左边的变量列表中的变量没有匹配上,如果没有设置默认值就返回undefined,如果设置了默认值就返回默认值。【默认值会在获取不到时生效】【获取对象中不存在的属性,使用变量时返回undefined。通过设置默认值,可以避免返回值为undefined。】 |
const {变量1名:变量别名,变量2名,…}=对象名 | 会将左边的变量名列表中的原变量名去和右边对象中的属性名进行值的匹配,匹配上就将右边对象对应的属性的属性值直接赋值给左边的变量。以后该作用域中就可以直接使用变量别名来获取对象中对应的属性的属性值了【有变量别名的原变量名将会失效】。没有变量别名的就直接使用变量名获取对应对象中的属性。 |
8 数组相关
8.1数组的方法
语法 | 描述 |
数组名.forEach(function(参数1,参数2,参数3){
}) | 第一个参数为遍历数组时的每一项 第二个参数为遍历到该项时的索引 第三个参数为遍历的数组值 三个参数都可以省略 返回值为undefined 推荐使用箭头函数写法 |
let 新数组名=数组名.map(function(参数1,参数2,参数3){ return 表达式 }) | 第一个参数为遍历数组时的每一项 第二个参数为遍历到该项时的索引 第三个参数为遍历的数组值 三个参数都可以省略 返回值为新数组【可以理解为每次循环依次往该新数组中追加return后面表达式返回值的结果】 基于一个数组->生成一个新数组【新数组的每一项,为map中每次循环return后面的返回值】 推荐使用箭头函数来写 该方法会在内存中开辟一个空间,相比forEach方法会消耗性能一点,所以能用forEach方法的就不要用map方法 |
数组名.join(“分隔符”) | 将数组转为字符串,数组中的各个数据用分隔符隔开。 |
//普通写法 let 新数组 = 数组名.filter(function(参数1,参数2,参数3){ //函数体 return 参数相关条件判定 }) //箭头函数写法 let 新数组 = 数组名.filter( (参数1,参数2,参数3)=>{ //函数体 return 参数相关条件判定 }) //箭头函数写法【只有一个参数且函数体只有return一行语句】 let 新数组 = 数组名.filter(参数=> 参数相关条件判定) | 第一个参数为遍历数组时的每一项 第二个参数为遍历到该项时的索引 第三个参数为遍历的数组值 三个参数都可以省略 返回值为新数组【可以理解为每次循环根据return后面的参数相关条件判定 判断本次循环是否满足条件判定,满足条件就将原数组中的数据追加到新数组中】【return 后面的条件判定返回值为true就追加到新数组中,返回值为false就过滤掉】 这个方法是一个实例方法【后面会讲什么是实例方法】【回调函数执行】 推荐使用箭头函数来写 如果一个都筛选不出来,返回值为空数组 |
const 变量名 = 数组名.find((参数1,参数2,参数3)=>{ //函数体 return 参数相关条件判定 }) | 第一个参数为遍历数组时的每一项 第二个参数为遍历到该项时的索引 第三个参数为遍历的数组值 三个参数都可以省略 返回值是满足条件判定的第一个原数组中的元素,没有满足条件的元素就返回undefined。 |
数组名.includes(目标元素) | 看目标元素是数组中的数据返回值为true;目标元素不是数组的数据返回值false |
let 变量名=数组名.sort(function(参数1,参数2){ return 参数1和2相关表达式 }) | 参数1为数组的前一项,参数2为数组的下一项,当return后面的表达式大于0按参数的比较属性或其本身正序排列数组项,否则倒序。 返回值为一个排序好的新数组【不会改变原数组】 |
//如果没有参数1的初始值,默认参数//1的初始值为数组的第一项,这时参//数2将会重数组的第二项算起 const 变量名=数组名.reduce(function(参数1,参数2,参数3,参数4){ return 参数相关条件表达式 },参数1的初始值) | 回调函数中的参数: 参数1为上一次回调函数的返回值 参数2为遍历数组时的每一项 参数3为遍历到该项时的索引 参数4为遍历的数组 返回值为最后一次return 后面表达式的返回值【我们常用该方法来获取数组中所有对象的属性之间的计算结果:包括累加】【计算总价】 |
const 变量名=数组名.every(function(参数1,参数2,参数3,参数4){ return 参数相关条件判定 }) | 参数1是数组的每一项 参数2是每一项的索引 参数3是调用该方法的数组 返回值为布尔值【数组中所有数据都满足条件判定,返回值为true,数组中有一项不满足条件判定就返回false】 循环次数为找到不满足的条件为止 |
8.2 数组扩展运算符
arr1为第一个数组,arr2为第二个数组
语法 | 描述 |
[…arr1,…arr2] | 将数组1和数组2所有数据合并成一个新的数组 |
…arr1 | 去掉数组字面量,只留数据列表【逗号分隔的数据】 |
8.2.1 数组扩展运算符的作用
作用 |
把数组展开 |
可以便捷的实现多个数组的合并 |
简化部分函数的传参 |
9 关于对象打印
输出的是对象【不展开获取的是原来的值】 |
输出的是 内存地址 |
点开他【展开对象】 输出的是堆中的值 |
10 解构应用场景
应用场景 | 代码案例 |
函数形参和实参解构匹配 | let obj={ msg:’城市信息’, list:[‘北京’,’上海’] } function func({msg,list}){ console.log(‘msg:’,msg) } func(obj) |
用一个变量保存,获取过来的对象中的数组数据 | let obj={ message:{}, data:[保存的对象列表] } {message,data}=obj |
10.1 一次性解构一个目标对象中所有属性的方法
步骤 | 过程 |
1 | 在控制台打印Object.keys(目标对象).join(“”)获取属性对应的变量列表 |
2 | const {粘贴第1步控制台输出的变量列表}=目标对象 |
11 常用扩展运算符和剩余参数应用场景
应用场景 | 案例 |
多个数组连接 | […数组1,…数组2] |
保存对象剩余属性和方法,得到新对象 | {属性1名,属性2名,.…parm}=对象名 |
保存数组剩余数据,得到新数组 | [变量1,变量2,…parm]=数组名 |
12 渲染数组数据到页面
data为数组名,data数组名里面保存着对象数据
步骤 | 代码示例 |
1.用map方法遍历数组数据,将原数组的每一项更改为具有标签结构的模板字符串,返回值给到新数组中的每一项【将存放单个对象所有数据的html结构拿过来,里面放我们的对象数据】 | let str=’’ let newArr = data.map(function(item){ return ` <开始标签>${item.属性1}</结束标签> <开始标签>${item.属性2}</结束标签> <开始标签>${item.属性3}</结束标签> <开始标签>${item.属性4}</结束标签> ` }) |
2.新数组通过join方法拼接为具有html结构的字符串 | let str=newArr.join(‘’) |
3.获取需要渲染到某个元素内部的标签 | const dom=document.querySelectorAll(‘选择器’) |
4.渲染到页面上 | dom.innerHTML=str |
13 对象
13.1 创建对象的三种方式
13.1.1 字面量创建对象
语法 | 描述 |
let 对象名 = { 属性1名:属性1值, 属性1名:属性1值, … } | 花括号的对象字面量里面添加属性和方法的方式赋值给变量保存的方式叫叫字面量创建对象。 |
13.1.2 构造函数
语法 | 描述 |
let 自定义对象名 = new Object() 自定义对象名.属性1名=属性1值, 自定义对象名.属性2名=属性2值, … | 通过new Object()构造函数的方式创建实例对象,通过实例对象.点的方式设置属性和方法 |
13.1.3 自定义构造函数
语法 | 描述 |
function 自定义构造函数名(){ this.自定义属性1名=自定义1形参, this.自定义属性2名=自定义2形参, … this.自定义方法1名=function(){ //方法体里面的this指向还是创建出来的实例对象 } } let 自定义对象名=new 自定义构造函数名(实参列表) | 通过自定义构造函数的方式创建对象,创建对象,只需new 自定义构造函数名调用即可。 |
14 构造函数
构造函数函数名 首字母大写
构造函数 会自动把创建的对象 返回出去
调用构造式 通过new关键字
构造函数内部的this是创建的对象【可以动态添加属性/方法,是实例成员。实例成员是独有的,可以用来接收保存的参数】【公共的方法不建议写在这里面,会浪费内存资源】
构造函数的属性和方法被称为‘静态成员’【静态成员是公共的,只要是由该构造函数创建出的对象,构造函数都可以调用该属性和方法】
14.1 作用
专门用来创建对象的函数 |
通过构造函数可以快速创建同一类型的对象 |
14.2 语法
语法 | 描述 |
function 构造函数名(参数1,参数2,…){ this.实例属性名=形参【自己选】, this.方法名=方法体 } 构造函数名.静态属性名=静态属性值; let 实例对象=new 构造函数名() | 构造函数函数体中设置的属性和方法为实例属性和方法,直接给构造函数设置的属性和方法为静态方法。 |
14.3 实例成员【构造函数内部this点出来的。】
实例化:创建对象的过程【new 构造函数名】
实例(化)对象:创建出来的对象【保存构造函数创建出来的对象的变量名】
实例成员:创建出来对象的属性和方法统称【实例属性:特指属性】【实例方法:特指方法】【一般设置 实例化对象 独有的 属性/方法】
14.3.1 示例描述
示例 | 描述 |
function Dog(name,food) { this.name=name, this.food=food } |
14.4 静态成员
构造函数的属性和方法被称为“静态成员”【构造函数点出来的】
构造函数可以动态添加属性和方法
语法 | 描述 |
构造函数名.属性名=属性值 | 设置的时候这样设置,使用的时候也需要用构造函数名.点的方式来使用【实例对象点的方式不行】 |
14.5 原型prototype
每个构造函数都有一个prototype属性,类型是对象
由构造函数实例化的对象可以使用原型上的属性和方法【同一个构造函数原型上的方法和属性的内存地址是一样的,通过实例对象.方法名的形式进行三个等的比较,比较的是内存地址,返回值是true。注意方法不要加括号。】
通过构造函数创建的实例对象,当实例对象调用原型上的目标方法时,这个目标方法内部的this指向为调用该原型方法的实例对象;用构造函数调用原型上的目标方法,目标方法内部的this指向为调用该原型方法的构造函数本身
原型通过构造函数访问,原型prototype上设置的属性/方法,实例化对象可以共享
数组实例方法来源:Array.prototype.方法名
querySelectorAll返回的伪数组为什么可以调用forEach方法:NodeList的原型上有该方法
14.6 原型方法和构造函数中的this指向
原型方法和构造函数中的this指向实例化对象
直接通过this即可访问
14.7 原型继承
prototype中的属性/方法后续所有的实例化对象都可以共享【将需要继承的属性和方法加给构造函数的prototype】
实例化的对象可以继承原型及原型链上的属性和方法
14.8 原型链
原型对象形成的链式结构称之为—原型链【原型链指的是原型对象形成的链式结构,以及在使用实例属性/方法】时检索的路径
实例对象调用方法时,会先看构造函数内部有没有该方法,有就用构造函数内部的属性或方法,没有就看构造函数名.prototype有没有该方法,有就用构造函数名.prototype上的方法,没有继续往原型链上找Object.prototype上找有没有该方法,有就有Object.prototype上的方法,没有就报错
14.9 实例属性__proto__
对象可以通过__proto__访问到原型prototype
实例对象.__proto__=自己构造函数名.prototype
15 内置构造函数Array和Object
15.1 创建数组
语法 | 描述 |
let 数组名 = new Array() | 通过内置构造函数Array创建数组 |
15.2 创建对象
语法 | 描述 |
let 对象名= new Object() | 通过内置构造函数Object创建对象 |
15.3 Object常用静态方法
语法 | 描述 |
Object.keys(目标对象名) | 返回值为目标对象中所有属性名组成的数组 |
Object.values(目标对象名) | 返回值为目标对象中所有属性值组成的数组,可以获取方法。 |
16 字符串的属性和方法
16.1 字符串的属性
语法 | 描述 |
字符串名.length | 获取字符串中字符的个数 |
16.2 字符串的方法
语法 | 描述 |
字符串名.split(‘分隔符’) | 将字符串按照分隔符切割为数组的每一项 |
字符串名.indexOf(‘检测字符或字符串’) | 检测字符串中是否由参数字符或字符串,有就返回该字符或字符串在字符串中的索引,没有就返回-1【只能检测第一个满足条件的索引】 |
字符串名.includes(‘检测字符’) | 检测字符【或字符串整体】【第一个参数的保存值】在字符串中是否存在,存在就返回true,否则返回值为false |
str.replace(reg,’替换文本’) | 在字符串str中找是否有满足正则的字符,有就替换为替换文本 |
17 回调函数
就是将函数作为另一个函数参数。
回调函数中的this指向为window
18 包装类型
JavaScript中的基本数据类型 字符串、数组、布尔值具有基本包装类。
18.1 包装类构造函数
String():字符串
Number():数字
Boolean():布尔
19 面向对象
完成比完美重要
19.1 面向对象vs面向过程
面向对象 | 面向过程 |
三大特性:封装、继承、多态 | 实现逻辑的过程【1. 逻辑语句; 2. 表达式;3 函数】 |
封装:【1. 创建一个对象,保存某一类的属性和功能;2. 更加利于维护和复用;3. 之后使用功能属性的时候,找对象:3.1 自己封装;3.2 别人封装好的】 | 封装的最高级别到function |
多态:同一个函数在不同情况下表现出的不同的状态【函数的重载,字类替换父类】 | JavaScript无法实现多态 |
20 深浅拷贝
深拷贝针对的是:Object,Array这一类的复杂类型数据
对象直接赋值给其他的变量,是将内存地址赋值给了变量保存,使用变量时变量会根据内存地址去获取值。
20.1 原理
先将对象或数组转为JSON字符串,再将JSON字符串转回对象或数组
开发中如果数据没有undefined和function就可以用
缺点:丢失目标对象中保存undefined和方法的属性【原因:JSON字符串无法保存undefined和function】
语法 | 描述 |
JSON.stringify(目标对象或目标数组) | 将目标对象或目标数组转为JSON格式的字符串【会丢失undefined值和方法。】【序列化】 |
JSON.parse(JSON格式字符串) | 将JSON格式的字符串转回对象或数组。【返回新对象】【反序列化】 |
20.2 浅拷贝
只拷贝一层
语法 | 描述 |
let 对象名={…原对象名} | 只拷贝第一层 |
20.3 深拷贝
对象的每一个层级的属性都是新的【拷贝对象也就是我们得新对象的对象名中属性和方法的修改不会影响原对象值得变化】,
20.3.1 深拷贝语法
原对象为obj,新对象为newObj
语法1 | 描述 |
let 变量1=JSON.stringify(原对象名obj) let 新对象名=JSON.parse(变量1) | 第一行代码:将原对象转为JSON格式的字符串 第二行代码:将转换过来得JSON格式字符串重新转为对象,返回给新对象保存【这个时候新对象里面的所有属性修改都不会影响原对象了,因为不存在有某个复杂数据保存的内存地址一样的问题。】【但是新对象里面不会有原对象中保存undefined的属性和保存方法的属性】 |
语法2 | 描述 |
function deepClone(oldObj) { const newObj = {}; for (let key in oldObj) { if (typeof oldObj[key] === "object") { newObj[key]=deepClone(oldObj[key]); } else { newObj[key] = oldObj[key]; } } return newObj; } | 1. 创建新对象newObj克隆原对象oldObj数据 2. for in循环遍历老对象,给新对象添加老对象的属性时同时给老对象属性添加值newObj[key] = oldObj[key]; 3. 如果老对象的属性值为对象,我们需要重新遍历一次 |
利用lodash语法 | 描述 |
<!-- 引入lodash.min.js文件 --> <script src="./lodash.min.js"></script> const 新对象名=_.cloneDeep(原对象名) | Lodash,一个流行的JavaScript工具库,提供了很多封装好的方法,可以直接调用,简化开发【都可以拷贝下来】 使用步骤: 1.导入函数库 2.调用_.deepClone()函数传入对象 3.获取拷贝的新对象 4.测试一下是否实现了深拷贝 |
20.4 递归
函数内部调用自己就是递归
递归约等于循环,都需要退出条件,避免无限循环或者无限递归
死递归,无法停止-->堆栈溢出
开发中常用于:1. 深拷贝;2. 数组转为树形数据; 3. 树形数据转回数组
语法 | 描述 |
function 目标函数名(){ 操作数 if(条件判定){ 目标函数名() } } |
21 throw
throw抛出异常信息后续代码不会执行
语法 | 描述 |
throw ‘异常信息’ | |
throw new Error(‘错误信息’) | 更常用 |
22 try-catch-finally处理异常 保证代码可以运行
语法 | 描述 |
try{ //可能出错的代码 }catch(error){ //出错后执行的代码 }finally{ //一定会执行 } | Ajax中会用到。 |
23 普通函数和箭头函数的this指向
普通函数this指向 | 箭头函数this指向 |
谁调用,this就指向谁,看不到调用者就指向window | 箭头函数内部的this指向上一个作用域中的this【对象不是作用域】 |
23.1 call方法
call是函数上的一个方法
调用call方法等同于调用函数,可以传入具体的this指向
语法 | 描述 |
目标函数名.call(this指向,参数2,参数3…) | 会先调用一次目标函数并将目标函数的this指向设置为第一个参数。 第二个参数开始,依次将后面的参数列表作为目标函数名的形参 |
Object.prototype.toString.call(变量名) | 返回值为[Object 数据类型]字符串可以根据该方法的返回值得到数据类型的字符串。 |
23.2 apply方法
语法 | 描述 |
Object.prototype.toString.apply(变量名) | 返回值为[Object 数据类型]字符串可以根据该方法的返回值得到数据类型的字符串。 |
23.3 bind函数
bind是函数上的一个方法
调用bind方法会返回一个绑定了this的函数,不会先调用。事件触发或者返回值函数调用才可以执行
语法 | 描述 |
let 自定义函数名=目标函数名.bind(目标函数名this指向) | 自定义函数名保存的是目标函数,不过改变了目标函数的this指向。但并不会改变目标函数,只是自定义函数名调用的时候,目标函数内部的this才会发生变化。 |
24 this指向面试题如何回答
this这个学编程的初期,困扰了我很久,一直不明所以,之后花了不少时间研究,终于搞明白了 |
普通函数:最为简单,谁调用就是谁,看不到谁调用就是window |
箭头函数:上一级作用域中的this,能够创建作用域的有if、for、{}【对象的花括号不行】、function |
call、apply都可以通过函数点出来 1.作用:调用函数并传入具体的this 2.call传递给函数的参数从第二个开始 3.apply传递给函数的参数,第二个参数,参数以数组的形式传入。可以简化Math.max的传参 4. 学了ES6之后,可以用…【扩展运算符可以简化Math.max的传参】 |
bind call和apply不一样,返回一个绑定了this的新函数 |
不过我在开发中没咋用过,用新技术挺好。 |
25 防抖和节流
防抖和节流都是开发中限制事件触发频率的一种手段【节约性能】【lodash有很多的简化方法】
25.1 节流throttle
规定在一个单位事件内,只能触发一次函数
如果这个单位时间内触发多次函数,只有一次生效【小米商城的轮播图】
自己写案例 | 描述 |
lodash节流语法 | 描述 |
<!-- 引入lodash.min.js文件 --> <script src="./lodash.min.js"></script> 元素名.addEventListener(‘事件类型’,_throttle(函数表达式或函数名,等待时间) | 等待时间间隔内事件只会触发一次 |
lodash节流案例 | 描述 |
<button>你好</button> document.querySelector("button").onclick = _.throttle(function () { console.log("别点了"); }, 2000); | 每两秒内只允许被点击一次 |
25.2 防抖debounce
在事件被触发n次后再执行回调
如果在这n秒内又被触发,则重新计时
自己写案例 | 描述 |
// 清除定时器 clearTimeout(timer) // 重新设置定时器 const timer = setTimeout(() => { //对输入框的相关事件处理 }, 300) | 主要用于输入框input事件中,为了防止事件在输入内容的时候频繁触发,我们需要共享同一个定时器变量,事件处理逻辑写在定时器中,而每次在开启定时器前都需要删掉定时器。 |
Lodash防抖语法 | 描述 |
<!-- 引入lodash.min.js文件 --> <script src="./lodash.min.js"></script> 元素名.addEventListener(‘事件类型’,_debounce(函数表达式或函数名,等待时间) | 元素在事件类型的触发下,只要在等待时间间隔之间事件类型没有被再次触发,就会执行该事件 |
26 常见场景
场景 | 描述 |
输入框中按下键盘enter键触发事件 | 给输入框注册keyup鼠标抬起事件,如果e.keyCode==13执行事件处理函数 |
下拉框select中的option【只有手动点击切换才会触发onchange事件,js修改不会触发】 | 当获取select元素的value值在option选项中存在时,select会自动切换到对应的option选项 |
第二章
1 服务器
在网上提供服务的计算机
平时一般见不到,但咱们经常和他保持着联系【1. 微信,QQ-->获取聊天的信息(微信/QQ的服务器);2. 听歌软件(网易云,QQ音乐)-->获取歌曲的信息(音乐服务器);3. 浏览器-->获取网页信息(网页服务器)】
1.1 通讯过程
以浏览器为例子
步骤 | 过程 |
1 | 浏览器:输入URL地址-->请求 |
2 | 服务器:接收请求并返回对应的资源-->响应 |
3 | 浏览器:接收并解析响应内容 |
4 | 可以在浏览器开发者界面的network分类查看 |
1.2 局域网中的服务器
在局域网可以访问的电脑
安装并启动可以提供web服务的软件(比如小皮面板里面的apache)
2 url
2.1 概念
url也叫做统一资源定位器【符】
是指定在Internet上可以找到资源的位置的文本字符串【网络资源的地址】
http:【协议】ajax-api.itheima.net【主机】:80【端口】/public/images/0.webp【资源路径】
2.2 协议名:
http://或https://【会加密,安全一些】开头
协议是网络协议的简称,用来保证通信的双方能读懂彼此发送过来的消息内容
2.3 主机【域名】
主机指的是在互联网(局域网)中提供服务的设备,可以通过ip或者域名访问
如果访问的是域名:DNS服务器解析-->ip地址【根据域名—找到对应的ip地址】
2.4 端口号
端口号是 0-65535之间的整数
计算机内部服务和外部通讯的虚拟通道
一个端口一次只能被一个服务占用(类比做核酸)
http默认的端口是80,可以省略不写
https默认的端口是443,可以省略不写
2.5 服务器上的资源
3. Ajax
3.1 概念
使用XML HttpRequest异步对象和服务器通讯。
Ajax是一种技术,可以在不重新刷新页面【不刷新浏览器】的情况下与服务器通信,交换数据,或更新页面【常见网站:京东、淘宝】
原生的写法较为繁琐,就有了一些封装好的请求库,可以简化这一操作
axios是目前最为流行的请求库【get请求+传递参数】,在浏览器端是基于Ajax封装【1. Ajax是技术,有原生的写法-->较为繁琐;2. Axios-->库,简化ajax的使用】
3.2 接口
使用ajax和服务器通讯时,被请求的URL地址,叫做 数据接口(接口,API接口、API)
Ajax请求的服务器一般称之为:接口服务器
接口服务器一般提供操纵服务器数据的一系列方法
调用(请求)接口有点类似于调用后端封装好的函数【then方法里面的参数获取的是筛选后的数据】
工作中接口一般由后端工程师编写,并提供接口文档指导调用
3.3 接口文档
作用:指导前端开发者如何和接口服务器通讯
文档内容:1. 服务器地址;2. 请求的方法【有了这两个就可以用Ajax和服务器交互;3. 根据需求可能会有更多的信息:3.1 接口参数,3.2 返回值格式,3.3 额外的设置等】
工作中接口一般由后端工程师编写,并提供接口文档指导调用【1.如何调用接口;2.如何用ajax和服务器通讯的;3.说明书】
3.4 axios语法
3.4.1 核心思路
什么时候发起请求【发起请求】:window.onload【页面加载完成】
什么时候获取响应【接收响应】:.then(res=>{//res数据渲染到页面逻辑})
语法1 | 语法2 |
//params属性的本质也是将参数拼接 //到url的末尾 axios.get(‘资源路径【url地址】’,{ params: { 请求参数1:请求参数值1, 请求参数2=请求参数值2, … } }).then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理请求失败的错误情况 }) | axios.get('资源路径【url地址】?资源路径?请求参数1=请求参数值1&请求参数2=请求参数值2&…').then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理错误情况 }) |
推荐写法axios-config模式get请求 | 推荐写法axios-config模式post请求 |
axios.({ url:'资源路径 ', method:’get’,//默认值,可以不写 params:{//参数根据接口文档来写 参数1:参数值1, 参数2:参数值2,… } }).then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理错误情况}) | axios.({ url:'资源路径 ', method:’post’, data:{//参数根据接口文档来写 参数1:参数值1, 参数2:参数值2,… } }).then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理错误情况}) |
then方法的第一个回调函数的参数是成功返回的数据
catch获取到的是错误,错误log无法看到内部的值,只能用dir看到。如果需要清除控制台报错,可以使用console.clear()来清除控制台错误
3.5 代码体验
axios .get("http://ajax-api.itheima.net/api/news", { // params 固定的 get请求传递参数 一定写在params params: { // pname 接口文档查到的 // 湖南省 使用接口 传递的具体的值 // pname: '湖南省' pname: "大连市", }, }) .then(function (response) { // 请求成功 执行 then中的逻辑 console.log("response:", response); let arr = response.data.data; }) .catch(function (err) { // 请求失败 执行 catch中的逻辑 console.log("err执行啦"); console.log(err); }); |
3.6 请求方法
客户端浏览器在请求服务时,根据操作性值的不同,可以分为以下5中常见的操作。
序号 | 请求方式 | 描述 |
1 | POST | 向服务器新增数据(传递) |
2 | GET | 从服务器获取数据 |
3 | DELETE | 删除服务器上的数据 |
4 | PUT | 更新服务器上的数据【侧重于完整更新:例如更新用户的完整信息】 |
5 | PATCH | 更新服务器上的数据【侧重于部分更新:例如只更新用户的手机号】 |
除了这5种以外还有一些其他的方法,比如OPTIONS,HEADER等【可以调用不同的接口,会不断印证方法作用】
3.6.1 axios的config模式
通过属性的方式设置请求需要的地址,方法和参数。
下面3.6.2和3.6.3有详细介绍。
3.6.2 axios的get请求
get请求一般是获取数据,根据接口文档来
get请求如果要传递参数,是拼接在url的末尾,格式要求:
语法格式 | 描述 |
//?后面那一坨也叫查询字符串 axios.get(‘url?key1=value1 & key2=value2’) | 参数拼接在url末尾,参数之间用&隔开,参数与url之间用?隔开 |
axios.get(‘url’,{ params:{ key1:value1, key2:value2 } }) | 参数写在第二个配置对象中,配置属性为params;配置好后,参数会自动拼接到url后面 |
推荐写法axios-config模式get请求 | 描述 |
axios.({ url:'资源路径 ', method:’get’,//默认值,可以不写 params:{//参数根据接口文档来写 参数1:参数值1, 参数2:参数值2,… } }).then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理错误情况 }) | 该方式写法为推荐写法 参数写在params配置属性中 |
3.6.3 axios的post请求
post请求一般是提交数据到服务器,根据接口文档来
语法格式 | 描述 |
axios.post(‘url?key1=value1 & key2=value2’) | 参数拼接在url末尾,参数之间用&隔开,参数与url之间用?隔开 |
axios.post(‘url’,{ key1:value1, key2:value2 } }) | 参数写在第二个对象中,参数会自动拼接到url后面 |
推荐写法axios-config模式post请求 | 描述 |
axios.({ url:'资源路径 ', method:’post’, data:{//参数根据接口文档来写 参数1:参数值1, 参数2:参数值2,… } }).then(function(形参){ //请求成功函数体【形参为成功数据】 }).catch(fucntion(error){ //处理错误情况 }) | 推荐写法 参数写在data属性配置中 |
3.6.4 当接口文档中有请求参数时【以get请求为例】
请求参数位置 | 书写位置 |
path | 请求参数写在params配置里面或者写在url路径后面 |
query | 请求参数只能写在params配置里面 |
3.7 axios-基地址【在调用axios之前设置】
设置基地址之后,请求的地址变为:基地址+url地址【字符串拼接】
设置基地址之后,后续的请求地址只需设置完整地址不同的部分即可
3.7.1 基地址适用场景【项目中的接口一般开头部分是一样的】
一般项目中使用【项目中多个接口的地址,开头部分一般相同】
3.7.2 语法
语法 | 描述 |
<!-- 引入 lib 目录下的 bootstrap 和 axios --> <script src="./lib/axios.js"></script> <!—设置基地址:完整地址的公共部分--> axios.defaults.baseURL="公共部分url"; axios({ url: "完整地址剩余部分url", method:’get’, params:{ 参数1名:参数1值, 参数2名:参数2值, … } }).then(function(){ //获取的数据操作 }) | 1.先引入axios请求库 2.设置基地址:axios.defaults.baseURL=’公共部分url’ 3.调用axios实现数据交互 |
4 报文
HTTP协议规定了客户端【浏览器】和服务端【服务器】通讯时传递的内容格式
双方在通讯时需要按照格式要求彼此才可以正常解析
客户端【浏览器】发送的叫做—请求报文
服务器响应的叫做—响应报文
和服务器通讯的过程是基于请求和响应来完成的,其中浏览器发送的和服务器响应的内容,都有一个统称—报文。
4.1 http状态码
开发中服务器响应的内容中除了响应体以外,还一个咱们需要重点关注的地方http状态码
http响应状态码【status code】由三位数字组成,用来标识响应成功与否的状态【响应状态码是由http协议规定的,具有通用性,每个不同的状态码都有其标准的含义,不能乱用。】
客户端浏览器根据响应状态码,即可判断这次http请求是成功还是失败了
所在位置是请求报文的状态行
请求成功和失败 后端通过返回不同的http状态码来区分
请求状态 | 表现 |
请求成功 | 绿色的成功 状态行 |
请求失败 | http错误状态码 状态行红色;浏览器红色的错误提示 |
4.2 常见状态码
客户端发送第1次请求给服务器,服务器响应成功返回响应状态码2XX;第2次请求,重定向返回响应状态码3XX;第3次请求客户端错误,服务器返回响应状态码4XX;第4次请求服务器错误,返回响应状态码5XX
状态码 | 状态码描述 | 说明 |
200 | Ok | 请求成功 |
201 | Created | 资源在服务器端已成功创建 |
304 | Not Modified | 资源在客服端被缓存,响应体中不包含任何资源内容 |
400 | Bad Request | 客户端的请求方式、或请求参数有误导致的请求失败 |
401 | Unauthorized | 客户端得用户身份认证未通过【未登录】,导致得此次请求失败 |
404 | Not Found | 客户端请求得资源地址错误,导致服务器无法找到资源 |
500 | Internal Sever Error | 服务器内部错误,导致得本次请求失败! |
4.3 业务状态码
业务状态码所处的位置是响应体中【预览或响应里面看】
业务状态码由后端定义的,不具有通用性【值可以根据需求更改,字段:code】
4.4 请求报文
组成:请求行【可以查看请求地址,请求方法,协议】、请求头【可以看到主机名,等一些其他的信息,大部分是自动生成】、请求体【传递给服务器的数据】
请求报文大部分都是自动生成,我们只需要设置必须的部分【1.请求的地址和提交的参数;2.关注请求体】
请求行在浏览器的控制面板->网络->Fetch/XHR->标头中看【请求头也在这里看】【请求头由浏览器结合axios自动生成。】【请求行是发请求时设置的】
请求体在浏览器的控制面板->网络-> Fetch/XHR->载荷中看【提交给服务器的数据】
4.5 响应报文
组成:状态行【成功/失败】、响应头、响应体【1.服务器返回的主要内容;2.不同的接口返回的内容是不一样的】
响应报文是服务器返回的,大多数时候只需要关注响应体即可【响应体:服务器返回的内容】
状态行在浏览器的控制面板->网络->Fetch/XHR->标头->响应标头->HTTP/开头查看状态【这里看到的是状态码】
响应体在浏览器的控制面板->网络-> Fetch/XHR->响应或预览中看【区别:响应是没有格式化的;预览是格式化了的】
4.6 请求响应相关业务补充
请求 | 响应 |
什么时候发请求 | 什么时候接数据 |
是否需要携带数据 | 接收到数据之后有什么逻辑 |
有没有额外的逻辑 |
4.7 接口风格
有一类接口,无论请求成功和失败 http状态码都是200。通过响应体中的 业务状态码判断本次执行的功能是否成功【优势:无论业务成功/失败,浏览器端一定不会报错,用户体验好一些】
4.8 响应状态码和业务状态码对比
响应状态码 | 业务状态码 |
在状态行中包含的状态码 | 在响应体中的数据中所包含的状态码 |
响应状态码只能表示这次请求的成功与否 | 业务状态码用来表示这次业务处理的成功与否 |
响应状态码由http协议规定,具有通用性,不同的状态码都有其标准的含义,不能乱用 | 业务状态码是后端程序员自定义的,不具有通用性 |
4.9 接口测试工具
介绍:apipost、apifox、postman功能上都是类似的
API文档、API调试、API Mock、API自动化测试
选用apifox原因:有中文,有网页版-无需安装。
4.9.1 apifox基本使用
基本使用 | 描述 |
创建团队 | |
创建项目 | |
调整地址,请求方法 | |
根据接口文档的请求参数栏的数据结构给apifox的请求参数栏的params设置对应的参数名和参数类型 | |
根据接口文档的请求参数在apifox的给body设置请求参数栏设置对应的请求参数类型以及示例值。 | 示例值即为发送请求的数据 |
点击发送 | 会将示例值发送,响应回对应的数据 |
5 FormData实例化对象
FormData是内置对象,可以直接使用【FormData的实例化对象通过append方法添加数据;FormData的实例化对象通过get获取添加的数据,通过get的目的是判断是否添加进去了。】
通常配合axios传递FormData类型的数据【直接将FormData实例化的对象用append方法添加接口文档的参数名和对应的参数值,最后直接将这个FormData实例对象当作配置项data的属性值即可】
5.1 基本语法
语法 | 描述 |
//通过FormData实例化对象 let 自定义实例对象名=new FormData() //给自定义实例对象名添加属性 自定义实例对象名.append("添加属性名", "添加属性值"); //获取自定义实例对象的添加属性【数据不存在得到的是null】 自定义实例对象名.get("添加属性名") | 通过new关键字实例化 .append(key,value)添加数据 .get(key)获取key对应的值 可以保存文件【file类型表单】 能够结合Ajax进行数据提交(上传文件) get方法的返回值为属性名保存的值 |
6 onchange事件
输入框:内容改变触发【人为选择,不是js控制】
文件域:选择新的文件时触发【人为选择,不是js控制】
select下拉框:【人为选择,不是js控制】
元素对象改变时触发【input表单元素绑定该事件,当input元素的表单输入框内容改变时触发该事件;input元素的file类型的表单元素,选择新的文件时触发该事件,accept标签属性引导查找文件方式,文件表单元素.files:伪数组,保存了选择的文件,索引从0开始,可以获取用户选择的文件】【type=file文件域,可以让用户选择文件,accept属性引导用户选择的文件image/*所有的图片,用户选择其他的文件无法限制】【accept标签属性只能推荐用户选择,不能限制】
7. Ajax+form
直接用form表单提交数据和用ajax最大的区别是:form表单提交数据会刷新页面,目前基本不用【ajax不会刷新页面的情况下和服务器交互】
7.1 如何阻止默认表单的行为【目的:避免form提交数据】
语法1【阻止按钮的默认行为】 | 描述 |
form元素中的button元素.onclick=function(e){ e.preventDefault() } | form元素中的button元素点击后默认有提交跳转页面功能 |
语法2【阻止表单的提交事件】 | 描述 |
目标form表单元素.addEventListener(“submit”,function(e){ e.preventDefault() }) | form表单注册onsubmit事件后,在点击内部的submit按钮时触发onsubmit事件,如果事件处理中第一行代码e.preventDefault()表单就不会有默认的方式提交数据,内部的点击事件在onsubmit事件触发前是无效的。 |
7.2 利用插件快速获取表单数据【display:none的表单元素也会拿到数据】
获取的表单数据是用对象的形式保存的标签name属性对应的属性值作为对象属性名,元素value值作为对象属性值【可以获取表单类型有:text、passward、selected对应的option选项的标签value属性值】【但不能获取文件类型file】
插件地址:https://www.npmjs.com/package/form-serialize
直接使用插件:serialize(目标表单元素)获取到的是name属性值以及name属性所在标签的value值通过&符号拼接起来的参数字符串【name属性1值=value1值&name属性2值=value2值…】参数及参数值通过&符号连接起来的字符串。
步骤 | 过程 |
1 | 引入form-serialize.js插件:<script src=’form-serialize.js路径’></script> |
2 | 使用变量保存数据:可以获取目标表单元素内部所有具有name属性的属性值,并将该属性值作为新对象的属性名;具有name属性的表单元素的用户填入数据会作为新对象对应属性名的属性值 const 自定义变量名=serialize(目标form表单元素,{hash:true}) |
3 | 自定义变量名保存的是对象,对象的属性名为具有name属性的表单元素的name标签属性对应的属性值;属性值为该name标签所在表单元素的value值。 |
7.3 FormData和file类型表单和axios的应用
当接口文档的参数为FormData类型数据时,则config模式的data属性对应的属性值需要使用FormData构造函数的实例对象,而参数就需要通过append的方式加在实例对象上面去【请求参数为multiparty-form-data时常用】
步骤 | 过程 |
1 | //引入axios库 <script src="axios.min.js路径"></script> |
2 | //创建一个FormData实例对象 const 自定义formdata实例对象=new FormData() |
3 | //给formdata数据类型添加接口文档对应的参数 自定义formdata实例对象.append(‘接口文档中的参数名’,文件元素.files[0])//文件元素可以使用e.target.files[0]或dom.files[0]获取 |
4 | //使用axios库发出请求,以新增为例 axios({ url: "请求地址", method: "post", data: 自定义formdata实例对象, }).then(function (e) { //成功获取到形参e响应数据的逻辑 }); |
8.补充内容:
8.1 变量声明优先级
const【栈不能改,栈保存的是内存地址,但对象里面的属性可以改】>let>var
8.2 动态创建的DOM元素绑定事件
事件委托-->事件绑定给 祖先元素
通过请求库数据动态创建的元素,主任务初始是获取不到元素的,所以动态创建的元素绑定事件需要通过已经存在的元素上通过事件委托来绑定。
通过数据渲染视图时,需要删除某个数据【有个唯一标识的属性】重新渲染即可更新视图,该唯一标识的属性需要给删除按钮加上一个自定义属性对应该唯一标识的属性【自定义属性的属性值 和 唯一标识属性的属性值 相同。】
8.3 自动触发另一个个元素的点击事件
通常下面的代码放在另一个元素的注册事件下面,当另一个元素的注册事件触发时,目标元素的点击事件都会触发。
语法 | 描述 |
目标元素.click() | 会自动触发目标元素的点击事件 |
9. content-type
原生ajax中的post请求提交请求数据的时候需要使用,告诉服务器接收什么类型的数据【请求参数默认的数据类型为text/plain;charset=UTF-8,我们需要根据接口文档设置对应的数据类型】
9.1 概念
不同接口对于提交数据格式的要求略有不同,咱们结合接口文档的要求,
Axios是一个网络请求库,内部有很多的逻辑
对于接口对于数据格式的要求,开发者只需传递对应格式的数据即可【其他的事情axios会帮我们做】。
在响应中content-type告诉客户端实际返回的内部的内容类型【浏览器根据这个判断如何解析】【服务器告诉浏览器返回的数据是什么格式】
在请求中content-type客户端告诉服务器端实际发送的数据类型。【浏览器告诉服务器提交的数据是什么格式】
Content-type在浏览器的控制面板->网络-> Fetch/XHR->标头->请求标头->content-type中看【请求头的作用:告诉服务器提交到服务器的数据格式,axios会自动设置,原生ajax需要自己设置。】
Content-type在浏览器的控制面板->网络-> Fetch/XHR->标头->响应标头->content-type中看【响应头的作用:服务器返回的数据格式】
9.2 提交数据的格式
接口文档中body参数描述 | 格式 |
multipart/form-data | new FormData() |
application/json | 写成对象-->axios会帮我们转为JSON |
application/x-www-form-urlencoded | key=value&key2=value2 |
9.3 请求中content-type对比
请求中的content-type的作用:告诉服务器,提交的内容是什么格式
使用axios库提交不同格式的数据时,content-type不需要开发者设置,axios调用后浏览器会自动生成【原生的post请求才需要我们手动设置:xhr.setRequestHeader(“content-type”,”application/json”),响应的数据我们可以在响应体的content-type看到数据类型,响应的数据如果是json数据,我们可以对其通过JSON.parse()方法将其转换为对象数据。】
我们只需要根据接口文档,提交对应的参数数据格式的请求数据就行
属性值 | 应用场景 |
application/x-www-form-urlencoded | 表单中不包含文件上传的场景,适用于普通数据的提交【查询字符串,在url后面,格式为key1=value1&key2=value2】 |
multipart/form-data | 表单中包含上传文件的场景 |
application/json | 上传json格式数据【文本类】 |
10 原生Ajax
10.1 原生ajax无参数使用步骤
步骤 | 过程 |
1 | // 1.实例化 异步对象 (小黄人 XHR)【不刷新页面发送请求】 const xhr = new XMLHttpRequest() |
2 | // 2.设置请求的 地址 和方法 xhr.open('请求方法','请求地址') |
3 | // 3.注册回调函数 服务器响应内容回来之后触发 xhr.addEventListener('load',function(){ console.log(xhr.response) }) |
4 | // 4.发送请求 xhr.send() |
10.2 原生ajax-get请求传参
通过get请求传递参数,传递查询字符串(querystring)
在url的末尾按照格式拼接参数即可
格式:url地址?key1=value1&key2=value2
10.3 原生ajax有参数使用步骤
小黄人的response属性就是服务器返回的响应数据
请求数据放在小黄人的send方法中作为实参传递给服务器。
步骤 | 过程 |
1 | // 1.实例化 异步对象 (小黄人 XHR) const xhr = new XMLHttpRequest(); |
2 | // 2.设置请求的 地址 和方法 xhr.open("get", "http://ajax-api.itheima.net/api/login"); |
3 | // 3.注册回调函数 服务器响应内容回来之后触发 xhr.addEventListener("load", function () { console.log(JSON.parse(xhr.response)); }); |
4 | const data = { username: "admin", password: "123455" }; |
5 | //4.发送请求 //将数据传递给服务器 xhr.send(JSON.stringify(data)); |
10.4 根据接口提交不同的数据格式
mutipart/form-data:FormData【需要new一个FormData实例化对象,通过append添加数据】
application/json:对象【axios会帮我们转为JSON】
application/x-www-form-urlencoded:key=value&key2=value【该方式写完整url】
10.5 原生ajax-post请求传参urlencoded
setRequestHeader设置请求头
send中的内容会在请求体中
步骤 | 过程 |
1 | open()方法之后通过xhr.setRequestHeader(key,value)的形式设置数据格式 |
2 | send()方法中传递具体的数据,需要和格式一致 |
10.6 ajax-post请求有参数使用步骤
post请求需要告诉服务器我们提交数据的格式是什么。【步骤4】,这样在提交数据前,浏览器会帮我们讲数据转换为服务器需要的数据格式
步骤 | 过程 |
1 | // 1.实例化 异步对象 (小黄人 XHR) const xhr = new XMLHttpRequest(); |
2 | // 2.设置请求的 地址 和方法 xhr.open("get", "http://ajax-api.itheima.net/api/login"); |
3 | // 3.注册回调函数 服务器响应内容回来之后触发 xhr.addEventListener("load", function () { console.log(JSON.parse(xhr.response)); }); |
4 | //请求体中携带数据 需要设置content-type请求头 //set设置 Request 请求Header头 //通过接口文档知道传递的参数是什么格式,通过设置请求头的//content-type告诉服务器数据的格式 xhr.setRequestHeader("content-type", "application/json"); |
5 | const data = { username: "admin", password: "123455" }; |
6 | //4.发送请求 //将数据传递给服务器 xhr.send(JSON.stringify(data)); |
11. promise
异步函数的执行,由于是异步的,不会阻塞“主线程代码“的执行
概念:Promise是异步编程的一种解决方案,比传统的解决方案—回调函数和事件更合理和更强大。所以Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果
11.1 特点
对象的状态不受外界影响
一旦状态改变,就不会再变,任何时候都可以得到这个结果
11.2 状态:
Promise 对象变量保存的对象状态和状态值只有一种。当调用构造函数的函数形参它的参数时,如果调用是在同步语句 里面,则状态值为成功状态或则失败状态,如果调用是在异步, 如定时器里面,则状态值为 pending【看 Promise 构造函数里面 的函数形参 它的形参 resolve 和 reject 的调用位置 如果是在同 步语句中,则状态为成功或失败状态,如果在异步语句中,则为 进行中状态】
11.2.1 Promise 对象代表一个异步操作,有三种状态:
pending(进行中) 此时操作尚未完成
fulfilled(resolve)(已成功) 异步操作成功
rejected(reject)(已失败) 异步操作失败
11.2.2 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
11.3 缺点
无法取消promise,一旦新建它就会立即执行,无法中途取消
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
当处于pending状态时,无法得知目前进展到哪一阶段(刚刚开始还是即将完成)
11.4 promise的基本使用
语法 | 描述 |
var promise实例对象变量= new Promise(function(resolve,reject){ if(条件表达式){ resolve(成功的状态值) }else{ reject(失败的状态值) } }) | promise 实例对象变量保存的对象状态【尖括号括起来的是promise对象状态】和状态值以及报错信息 |
11.4.1 控制台promise对象状态
promise对象只有一种状态
状态 | 描述 |
<pending> | 表示进行中 |
<fulfilled> | 表示已成功【resolve(成功的状态值)已执行】 调用then方法,then方法内部的形参为调用该then的promise对象中的成功的状态值 |
<rejected> | 表示已失败【reject(失败的状态值)已执行】 调用catch方法,catch方法内部的形参在catch的回调函数内部表示调用该catch的promise对象中的失败的状态值 |
12 Promise构造函数
该构造函数的参数为回调函数,这个回调函数有两个形参:
形参 | 描述 |
第一个形参 | 成功状态函数名,该函数名调用后 该构造函数创建的实例对象会得到该函数参数的状态值 |
第二个形参 | 失败状态函数名,该函数名调用后 该构造函数创建的实例对象会得到该函数参数的状态值 |
12.1 Promise 实例对象的 then 方法
调用该方法,它的状态会是由 Promise 构造 函数中的形参函数 它的形参第一个 resolve 或 reject 回调函数执行后的状态 确定执行 then 方法的哪一个形参函数【同步异步都处理后的状态,由这个状 态确定调用 then 方法的哪个形参函数】
传递两个参数: 第一个参数是函数,用于 promise 实例对象 接收成功执行的代码块 i. 函数第一个形参在函数体内表示成功的状态值 ; 第二个参数是函数,用于接收失败执行的代码块【报错信息将不会在 控制台出现】
12.2 谈一谈你对Promise的理解
理解 | 描述 |
第一层 | 多个异步的逻辑,彼此依赖【接口2需要等待接口1,接口3需要等待接口2】 |
可能会出现的回调函数嵌套 | |
如果嵌套的较多,也可以成为回调地狱 | |
使用Promise之后,编码的风格变为-->链式编程,一路.then,.catch | |
第二层 | 基本用法:实例化Promise对象,内部执行异步的逻辑,根据成功/失败调用resolve或reject,这两个方法的本质是修改Promise对象的状态。 |
状态成功调用then方法,状态失败调用then的第二个回调函数或.catch方法 | |
Promise.all([pro对象1,pro对象2,…]).then(res=>)res为Promise数组中为每一个对象的成功结果 | |
Promise.race([pro对象1,pro对象2,…])等待第一个,但没有结合具体的业务场景,可以请教一下吗 | |
第三层 | 自己手写一个promise |
12.3 Promise构造函数的静态方法
语法 | 描述 |
Promise.all([promise参数列表]) | Promise.all方法的参数为数组,且数组的每一项都为promise对象 参数列表的所有promise对象都为成功状态,则返回值为成功状态的promise对象,状态值为所有参数列表的promise对象的成功状态值组成的数组集合 |
Promise.race([promise参数列表]) | Promise.race方法的参数为数组,且数组的每一项都为promise对象 返回值为第一个执行且状态为成功的promise对象 |
12.3.1 静态方法使用场景
两个静态方法的参数都为数组,且数组项为promise对象
方法 | 使用场景 |
Promise.all([promise参数列表]) | 页面中的数据来源于多个接口,需要等待多个接口都获取到结果之后才可以渲染 Promise.all([接口1,接口2,…]) |
Promise.race([promise参数列表]) | 某个功能需要调用接口,多个服务器都有这个接口,考虑网速,服务器稳定性的问题,多个接口都可以实现功能一样,我们可以通过该方法获取速度最快的接口数据。 |
13 Then 方法
如果一个对象实现了 then 方法,这个对象就被称为 thenable 对象,所有的 promise对象都是 thenable 对象,但是并非所有的 thenable 对象都是 promise
Promise 的 then()方法返回值还是一个 promise 对象,并且默认是成功状态,值为return 后面的值。没有 return 返回值时默认成功状态值为 undefined。
只有有状态值的 promise 实例对象才可以调用 then 方法【构造函数 Promise 创建的实例对象需要执行构造函数的函数参数[这样才有状态值]才有 then 方法,实例对象 promise 调用 then 方法返回的 promise 对象,可以连续调用 then 方法,因为默认状态值为成功状态,值为 undefined】
13.1 Promise实例对象的then方法的参数
第一个参数为成功状态的函数,这个函数的第一个形参在函数体内为调用then 方法的这个 promise 实例对象的成功状态值【成功执行形参第一个函数体内代码】
第二个参数为失败状态的函数,该函数的第一个形参在函数体内为调用 then方法的这个 promise 实例对象的失败状态值【失败执行形参第二个函数体内代码】
上面两个函数参数只执行一个或都不执行【promise 实例对象的状态为成功,
即 Promise 构造函数创建的实例对象执行了该构造函数的第一个参数函数,则
实例对象执行 then 方法的第一个参数函数,否则执行 then 方法的第二个参数
函数。】
Promise构造函数创建出来的promise实例对象的状态值由Promise构造函数的两个回调函数的执行情况确定。Promise构造函数的第1个回调函数执行,则为创建1个成功状态的promise对象,成功状态值为第1个回调函数调用的实参值【Promise构造函数的第2个回调函数执行,则为创建一个失败状态的promise对象,失败状态值为第2个回调函数调用的实参值】。promise实例对象调用then方法的返回值为promise对象,状态值为 上一个promise实例对象调用then方法中的回调函数的函数体的return后面的值。
14 补充
14.1 回调函数
把一个函数当作参数传递,将来特定的时机调用,这个函数就叫回调函数
把函数当作参数传递,被传递的那个函数-->回调函数
14.2 回调函数嵌套
回调函数嵌套概念:多个异步操作,彼此依赖
回调函数嵌套足够多形成回调地狱
14.3 常见异步函数
优先级 | 异步函数 |
1 | setTimeout |
2 | setInterval |
3 | 原生ajax |
14.4 promise链式调用
Promise对象的then方法如果返回了promise对象,可以再后面继续点链式调用
Then方法内部返回promise对象,promise对象可以.then
最终形成.then().then()…这种链式结构
15 同步异步代码执行顺序
事件是微任务
步骤 | 顺序 |
1 | 先执行主线程代码 |
2 | 执行本次产生的微任务 |
3 | 执行宏任务【宏任务在 主线程和微任务中的 优先级是一样的,有时间间隔的先看时间间隔,没有时间间隔的看代码书写顺序】 |
4 | 然后执行该宏任务产生的微任务 |
5 | 若微任务的执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后 |
6 | 再回到宏任务中进行下一轮循环 |
15.1 宏微任务
浏览器端宏任务主要有:setTimeout,setInterval
浏览器端的微任务主要有:Promise【的then方法中的回调函数】
16 async函数&await
async关键字写在function关键字的前面,当调用有async关键字的目标函数名时,会返回一个promise对象,该promise对象的状态为目标函数的return后面的值。
16.1 async含义
ES2017标准引入了async函数,使得异步操作变得更加方便
Async函数是generator函数的语法糖
16.2 async的使用
语法 | 描述 |
async function 目标异步函数名(){ await promise实例对象 return 返回值 } | 调用目标异步函数名时,会将return的返回值 不是promise对象就会包装为一个成功状态的Promise对象【返回值是promise对象就是得到这个promise对象】 且await后面的promise会执行完then中的异步代码后才会继续执行后续的同步代码【必须让await后面的promise对象执行完毕才会执行后面的同步代码】 |
16.3 async函数捕获异常
语法 |
try { //可能报错的代码 }catch(err){ //如果try中的代码有错就会执行这里的代码,参数err是报错信息 } |
17 bootstrap-modal组件
17.1 属性控制
自定义属性 | 作用 |
data-bs-toggle=”modal” | 切换modal弹框 |
data-bs-target=”#id名” | 控制哪个元素弹框【点击该元素,对应id名的元素模态框会弹出来】 |
17.2 模态框
刚开始复制过来的模态框html结构默认是隐藏的,通过点击目标元素可以控制模态框的显示与隐藏
创建目标模态框语法 | 描述 |
var 自定义创建的模态框名 = new bootstrap .Modal(document.querySelector('选择器')) | 通过选择器创建一个和选中元素一样【元素和子孙后代完全一样】的模态框 |
显示模态框语法 | 描述 |
自定义创建的模态框名.show() | 显示模态框【需要写在事件内部】 |
隐藏模态框的语法 | 描述 |
自定义创建的模态框名.hide() | 隐藏模态框【需要写在事件内部】 |
17.3 适用场景
属性控制的适用场景:没有逻辑,就希望 显示/隐藏的时候可以通过属性控制
js控制的适用场景:有逻辑,不仅要显示/隐藏,还要执行其他的逻辑
18 通过对象数据属性获取相关表单元素且填入默认值
18.1 当一层对象数据和表单元素一一对应时
语法 | 描述 |
for (let key in object) { document.querySelector(`[name=${key}]`).value = object[key]; } | object为遍历的数据对象 |
18.2 当一层对象数据比表单元素多了部分属性时
语法 | 描述 |
进度day03 | 15 |
1
标签:函数,对象,高级,4js,参数,请求,构造函数,属性 From: https://www.cnblogs.com/BlueGirl/p/17013564.html