JS原理-笔记(1/3)
JS原理-笔记(1/3)
知识点自测
今天课程中涉及到的已学习知识点
- 函数的
call
方法-文档链接
// 以指定的this调用函数,并通过 从第二个参数开始依次传递参数
function func(food,drink){console.log(this)console.log(food)console.log(drink)
}
const obj = {name:'小黑'
}
func.call(obj,'西蓝花','咖啡')
- 函数的
apply
方法-文档链接
// 以指定的this调用函数,并通过 数组的形式 传递参数
function func(food,drink){console.log(this)console.log(food)console.log(drink)
}
const obj = {name:'小黑'
}
func.apply(obj,['西蓝花','咖啡'])
- 函数的
bind
方法-文档链接
function func(food, drink) {console.log(this)console.log(food)console.log(drink)
}
const obj = {name: '小黑'
}
const bindFunc = func.bind(obj, '花菜')
bindFunc('可乐')
- 剩余参数-文档链接
function func(...args){console.log(args)// 以数组的形式获取传入的所有参数
}
func('西蓝花','西葫芦','西洋参','西芹')
- Promise核心用法-文档链接
const p = new Promise((resolve, reject) => {setTimeout(() => {const num = parseInt(Math.random() * 10)if (num > 5) {resolve(`成功啦--${num}`)} else {reject(`失败啦--${num}`)}}, 1000)
})
p.then(res => {console.log(res)
}, err => {console.log(err)
})
- URLSearchParams核心用法-文档链接
// 实例化时支持传入JS对象
const params = new URLSearchParams({ name: 'jack', age: 18 })
// toString方法 返回搜索参数组成的字符串,可直接使用在 URL 上。
console.log(params.toString())
- Object.create核心用法-文档链接
const person = {name: 'itheima',foods: ['西蓝花', '西红柿', '西葫芦']}// 将传入的对象作为原型,创建一个新对象(浅拷贝)const clone = Object.create(person)clone.name = 'itheima'clone.foods.push('西北风')console.log(clone.foods === person.foods)// true
- Object.assign核心用法-文档链接
const person = {name: 'itheima',foods: ['西蓝花', '西红柿', '西葫芦']}const son = {name: 'rose',}// 参数1 目标对象// 参数2 源对象// 将源对象的自身属性复制到目标对象,并返回目标对象const returnTarget = Object.assign(son, person)console.log(returnTarget === son)// trueconsole.log(son.name)// itheimaconsole.log(son.foods === person.foods)// true
JS中的this
这一节咱们来学习JS中this相关的知识点
传送门:MDN-this
传送门:MDN-call
传送门:MDN-apply
传送门:MDN-bind
传送门:MDN-箭头函数
传送门:MDN-剩余参数
传送门:MDN-Symbol
这一节咱们会学习的有:
- 如何确认
this
指向 - 如何改变
this
指向 - 手写
call
,apply
,bind
如何确认this的值:
在非严格模式下,总是指向一个对象,在严格模式下可以是任意值,开启严格模式可以使用如下两种方式:
- 在整个脚本顶部开启
- 在函数顶部开启
// 为整个脚本开启严格模式
'use strict'
function func() {// 为函数开启严格模式'use strict'
}
然后就可以根据不同的模式来确认this指向啦,
-
全局执行环境中,指向全局对象(非严格模式、严格模式)
-
函数内部,取决于函数被调用的方式
-
直接调用的this值:
- 非严格模式:全局对象(window)
- 严格模式:undefined
-
对象方法调用的this值:
- 调用者
-
// 1.全局执行环境
// 非严格模式: 不做任何设置,直接写就是非严格模式
// console.log(this) // window
// 严格模式: 代码顶部加上 'use strict' 即可
// 'use strict' // 为整个脚本开启严格模式
// console.log(this) // window// 2.函数内部
// 2.1 直接调用-非严格模式
// function func() {
// console.log(this) // 全局对象window
// }
// func()// 2.1 直接调用-严格模式
// function func() {
// 'use strict'
// console.log(this) // undefined
// }
// func()// 2.2 对象方法调用
// const food = {
// name: '猪脚饭',
// eat() {
// console.log('吧唧吧唧')
// console.log(this)
// }
// }
// food.eat()
面试回答:
如何确认this指向:
-
全局执行环境中,指向全局对象(非严格模式、严格模式)
-
如何开启严格模式:
// 为整个脚本开启严格模式 'use strict' function func() {// 为函数开启严格模式'use strict' }
-
函数内部,取决于函数被调用的方式
-
直接调用的this值:
- 非严格模式:全局对象(window)
- 严格模式:undefined
-
对象方法调用时的this值为调用者
-
如何改变this指向
主要有2类改变函数内部this
指向的方法:
-
调用函数并传入具体的
this
:-
call
:- 参数1:
this
- 参数2-n:传递给函数的参数
- 参数1:
-
apply
-数组作为参数- 参数1:
this
- 参数2:以数组的形式,传递给函数的参数
- 参数1:
-
-
创建绑定
this
的函数:- bind:返回一个绑定了
this
的新函数 - 箭头函数:最近的this是谁,就是谁
- bind:返回一个绑定了
调用函数并传入具体的this:
function funcA(p1, p2) {console.log('funcA-调用')console.log(this)console.log('p1:', p1)console.log('p2:', p2)
}
const obj = {name: 'jack'
}
// call参数
// 参数1 this值
// 参数2-参数n 挨个传入函数的参数
funcA.call(obj, 1, 2)
// apply参数
// 参数1 this值
// 参数2 以数组的形式传入函数的参数
funcA.apply(obj, [3, 4])
创建绑定this的函数:
function funcB(p1, p2) {console.log('funcB-调用')console.log(this)console.log('p1:', p1)console.log('p2:', p2)
}
const person = {name: 'itheima'
}
// bind参数
// 参数1 this值
// 参数2-参数n 绑定的参数
const bindFuncB = funcB.bind(person, 123)
bindFuncB(666)const student = {name: 'lilei',sayHi: function () {console.log(this)// 箭头会从自己作用域链的上一层继承thisconst inner = () => {console.log('inner-调用了')console.log(this)}inner()}
}
student.sayHi()
面试回答:
如何改变this
指向,有2类改变this
指向的方法,分别是:
-
调用函数时并传入具体的
this
-
call
:从第二个参数开始挨个传递参数 -
apply
:在第二个参数以数组的形式传递参数
-
-
创建函数时绑定
this
?-
bind
:返回一个绑定了this
以及参数(可选)的新函数 -
箭头函数:创建时会绑定上一级作用域中的
this
-
手写call方法
这一节咱们来实现myCall
方法,实际用法和call
方法一致,核心步骤有4步
const person = {name: 'itheima'
}
function func(numA, numB) {console.log(this)console.log(numA, numB)return numA + numB
}
// 参数1:指定的this值
// 参数2-参数n:原函数参数
const res = func.myCall(person, 2, 8)
console.log('返回值为:', res)
- 如何定义
myCall
? - 如何让函数内部的
this
为某个对象? - 如何让
myCall
接收参数2-参数n? - 使用Symbol调优
myCall
?
// 1. 如何定义`myCall`
Function.prototype.myCall = function () {// 逻辑略
}// 2 设置this并调用原函数
Function.prototype.myCall = function (thisArg) {// this 是调用myCall的 函数// thisArg 指定的this// 为他添加一个自定义属性,让函数成为他的该属性thisArg['fn'] = this// 调用并获取结果const res = thisArg['fn']()// 移除添加的自定义属性delete thisArg['fn']}// 3 接收剩余参数并返回结果
Function.prototype.myCall = function (thisArg, ...args) {thisArg['fn'] = this// 调用并获取结果const res = thisArg['fn'](...args)// 移除添加的自定义属性delete thisArg['fn']// 返回调用结果return res
}// 4 使用`Symbol`调优`myCall`
Function.prototype.myCall = function (thisArg, ...args) {// 使用Symbol生成唯一标记,避免和原属性冲突const fn = Symbol()thisArg[fn] = thisconst res = thisArg[fn](...args)// 移除添加的自定义属性delete thisArg[fn]// 返回调用结果return res
}// --------测试代码--------
const person = {name: 'itheima'
}
function func(numA, numB) {console.log(this)console.log(numA, numB)return numA + numB
}
// 参数1:指定的this值
// 参数2-参数n:原函数参数
const res = func.myCall(person, 2, 8)
console.log('返回值为:', res)
面试回答:
手写call方法的步骤为
- 在
function
的原型上添加myCall
方法,保证所有函数都可以调用 - 方法内部,通过动态为对象添加方法的形式来指定
this
指向 - 调用完毕之后通过
delete
关键字删除上一步动态增加的方法 - 方法的名字通过Symbol进行设置,避免和默认名重复
- 使用剩余参数的形式传递参数2-参数n(函数参数)
Function.prototype.myCall = function (thisArg, ...args) {const fn = Symbol()thisArg[fn] = thisconst res = thisArg[fn](...args)delete thisArg[fn]return res
}
手写apply方法
这一节咱们来实现myApply
方法,实际用法和apply
方法一致,核心步骤依旧4
步
const person = {name: 'itheima’
}function func(numA, numB) {console.log(this)console.log(numA, numB)return numA + numB
}const res = func.myApply(person, [2, 8])
console.log('返回值为:', res)
-
如何定义
myApply
?- 定义在原型上
-
如何让函数内部的
this
为某个对象?- 动态给对象添加方法,通过
对象.方法()
调用即可 - 使用
Symbol
来生成方法名
- 动态给对象添加方法,通过
-
如何让
myApply
接收参数?- 定义参数2即可
- 传递给原函数时需要使用
...
展开
// 1. 如何定义`myApply`
Function.prototype.myApply = function () {// 逻辑略
}// 2 如何让函数内部的`this`为某个对象
Function.prototype.myApply = function (thisArg) {// 为他添加一个自定义属性,让函数成为他的该属性// 使用Symbol生成唯一标记,避免和原属性冲突const fn = Symbol()thisArg[fn] = thisconst res = thisArg[fn](...args)// 移除添加的自定义属性delete thisArg[fn]// 返回调用结果return res
}// 3 如何让`myApply`接收参数
Function.prototype.myApply = function (thisArg, args) {const fn = Symbol()thisArg[fn] = this// 调用并获取结果// 用... 将args展开传入const res = thisArg[fn](...args)delete thisArg['fn']// 返回调用结果return res
}// 测试代码
const person = {name: 'itheima’
}function func(numA, numB) {console.log(this)console.log(numA, numB)return numA + numB
}const res = func.myApply(person, [2, 8])
console.log('返回值为:', res)
面试回答:
手写apply方法
- 在
function
的原型上添加myApply
方法,保证所有函数都可以调用 - 方法内部,通过动态为对象添加方法的形式来指定
this
指向 - 调用完毕之后通过
delete
关键字删除上一步动态增加的方法 - 方法的名字通过Symbol进行设置,避免和默认名重复
- 直接使用数组传递函数的参数,内部调用时结合
...
运算符展开数组
Function.prototype.myApply = function (thisArg, args) {const fn = Symbol()thisArg[fn] = thisconst res = thisArg[fn](...args)delete thisArg[fn]return res
}
手写bind方法
这一节咱们来实现myBind
方法,实际用法和bind
方法一致,核心步骤为2步
const person = {name: 'itheima'
}function func(numA, numB, numC, numD) {console.log(this)console.log(numA, numB, numC, numD)return numA + numB + numC + numD
}const bindFunc = func.myBind(person, 1, 2)const res = bindFunc(3, 4)
console.log('返回值:', res)
- 如何返回一个绑定了
this
的函数? - 如何实现绑定的参数,及传入的参数合并?
// 1 如何返回一个绑定了`this`的函数
Function.prototype.myBind = function (thisArg) {// myBind函数调用时,this就是函数本身 return () => {// 通过call方法将传入的 thisArg 作为this进行调用this.call(thisArg)}
}// 2 如何实现绑定的参数,及传入的参数合并
// ...args 接收绑定参数
Function.prototype.myBind = function (thisArg, ...args) {// ...args2 接收调用时的参数return (...args2) => {// thisArg 需要指定的this// args 调用myBind时传入的参数// args2 调用新函数时传入的参数return this.call(thisArg, ...args, ...args2)}
}// 测试代码
const person = {name: 'itheima'
}function func(numA, numB, numC, numD) {console.log(this)console.log(numA, numB, numC, numD)return numA + numB + numC + numD
}const bindFunc = func.myBind(person, 1, 2)const res = bindFunc(3, 4)
console.log('返回值:', res)
面试回答
手写bind方法
function
原型上添加myBind
函数,参数1为绑定的this,参数2-参数2为绑定的参数- 内部返回一个新箭头函数,目的是绑定作用域中的this
- 返回的函数内部,通过
call
进行this和参数绑定 - 通过
call
的参数2和参数3指定绑定的参数,和调用时传递的参数
Function.prototype.myBind = function (thisArg, ...args) {return (...args2) => {return this.call(thisArg, ...args, ...args2)}
}
JS继承-ES5
这一节咱们来学习如何在JS中实现继承,首先看看在ES6之前可以如何实现继承
传送门:继承与原型链
传送门:继承(计算机科学)
传送门:JavaScript高级程序设计
传送门:MDN-Object.create
传送门:MDN-Object.assign
**继承:**继承可以使子类具有父类的各种属性和方法,而不需要再次编写相同的代码
这一节咱们会学习ES5中常见的继承写法(命名来源于 《JavaScript高级程序设计》)
- 原型链实现继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
// 父类
function Parent(){this.name = namethis.foods = ['西蓝花', '西红柿']this.sayFoods = function () {console.log(this.foods)}
}
ES5-原型链实现继承
**核心步骤:**希望继承谁,就将谁作为原型
**缺点:**父类中的引用数据类型,会被所有子类共享
// 父类
function Parent(name) {this.name = namethis.foods = ['西蓝花', '西红柿']this.sayFoods = function () {console.log(this.foods)}
}
// 子类
function Son() {
}
// 将父类的实例 作为子类的原型
Son.prototype = new Parent('jack')
const s1 = new Son()
s1.sayFoods()// ['西蓝花', '西红柿']const s2 = new Son()
s2.sayFoods() // ['西蓝花', '西红柿']s2.foods.push('西葫芦')s2.sayFoods()// ['西蓝花', '西红柿', '西葫芦']
s1.sayFoods()// ['西蓝花', '西红柿', '西葫芦']
面试回答:
ES5-原型链实现继承
- 将父类的实例作为子类的原型实现继承
- 这种继承方法的缺点是父类中的引用类型数据会被所有子类共享
ES5-构造函数继承
**核心步骤:**在子类的构造函数中通过call
或apply
父类的构造函数
**缺点:**子类没法使用父类原型上的属性/方法
// 父类
function Parent(name) {this.name = name
}
Parent.prototype.sayHi = function () {console.log('你好,我叫:', this.name)
}// 子类
function Son(name) {Parent.call(this, name)
}const s1 = new Son('lucy')
const s2 = new Son('rose')
s1.sayHi() // 报错
面试回答:
ES5-构造函数继承
- 在子类的构造函数中通过
call
或者apply
调用父类的构造函数 - 这种继承方法的缺点是:子类没法使用父类原型上的属性/方法
ES5-组合继承
通过组合继承,结合上面2种方法的优点
核心步骤:
- 通过原型链继承公共的属性和方法
- 通过构造函数继承实例独有的属性和方法
**特点:**调用了2次构造函数
// 父类
function Person(name) {this.name = name
}
// 方法加父类原型上
Person.prototype.sayHi = function () {console.log(`你好,我叫${this.name}`)
}
// 子类构造函数
function Student(name, age) {// 调用父类构造函数传入thisPerson.call(this, name)// 子类独有的属性和方法单独设置this.age = age
}
// 设置子类的原型为 父类实例
Student.prototype = new Person()
// 调用子类的构造函数
const s = new Student('李雷', 18)
// 可以使用原型链上的 属性和方法 也可以使用 通过构造函数获取的父类的属性和方法
面试回答:
ES5-组合继承
-
组合继承的核心步骤有2步:
- 通过原型链继承公共的属性和方法
- 通过构造函数继承实例独有的属性和方法
-
组合继承的特点:调用2次父类的构造函数,浪费性能
ES5-原型式继承
直接基于对象实现继承
**核心步骤:**对某个对象进行浅拷贝(工厂函数或Object.create),实现继承
**缺点:**父类中的引用数据类型,会被所有子类共享
// 可以用 Object.create替代
function objectFactory(obj) {function Fun() { }Fun.prototype = objreturn new Fun()
}
const parent = {name: 'parent',age: 25,friend: ['rose', 'ice', 'robot'],sayHi() {console.log(this.name, this.age)}
}
const son1 = objectFactory(parent)
const son2 = objectFactory(parent)
son1.friend.push('lucy')
console.log(son2.friend)
面试回答:
ES5-原型式继承
- 原型式继承的核心步骤是:对某个对象进行浅拷贝,可以通过内置api
Object.create
实现,不需要调用构造函数即可实现继承,主要针对于继承对象的情况 - 原型式继承的缺点是:父类中的引用数据类型,会被所有子类共享
ES5-寄生式继承
核心步骤:
定义工厂函数,并在内部:
- 对传入的对象进行浅拷贝(公共属性/方法)
- 为浅拷贝对象增加属性/方法(独有属性/方法)
function createAnother(origin) {// Object.create基于原型创建新对象,对属性进行浅拷贝const clone = Object.create(origin)// 为对象增加属性/方法clone.sayHi = function () {console.log('你好')}return clone
}
const parent = {name: 'parent',foods: ['西蓝花', '炒蛋', '花菜']
}
const son1 = createAnother(parent)
const son2 = createAnother(parent)
面试回答:
寄生式继承
-
寄生式继承的核心步骤是:基于对象创建新对象(可以使用
Object.create
),并且为新创建的对象增加新的属性和方法 -
寄生式继承和上一节学习的原型式继承的区别是:创建出来的新对象,会额外的增加新的属性/方法
ES5-寄生组合式继承
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型 原型的一个副本而已。
核心步骤:
- 通过构造函数来继承属性
- 通过原型链来继承方法
// 继承原型函数
function inheritPrototype(son, parent){const prototype = object.create(parent.prototype)prototype.constructor = sonson.prototype = prototype
}// 父类
function Parent(name) {this.name = namethis.foods = ['西蓝花', '西葫芦', '西红柿']
}Parent.prototype.sayHi = function () {console.log(this.name, `我喜欢吃,${this.foods}`)
}// 子类借用父类的构造函数
function Son(name, age) {Parent.call(this, name)this.age = age
}
// 完成原型继承
inheritPrototype(Son,Parent)
// 可以继续在原型上添加属性/方法
Son.prototype.sayAge = function () {console.log('我的年龄是', this.age)
}const son1 = new Son('jack', 18)
const son2 = new Son('rose', 16)
面试回答:
ES5-寄生组合式继承
- 寄生组合式继承的核心步骤是:通过构造函数来继承属性,通过原型链来继承方法
- 寄生组合式继承和组合式继承的区别是:原型链的继承并没有调用父类的构造函数,而是直接基于父类的原型创建一个新副本实现继承
JS继承-ES6
这一节咱们来学习在ES6中class关键字的使用,并且使用它来实现继承
传送门:mdn类
传送门:阮一峰ES6-class
传送门:mdn-super
ES6中推出了class
类,是用来创建对象的模板.class
可以看作是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
这一节咱们会学习:
- class核心语法
- class实现继承
- class语法补充
class核心语法
核心语法:
- 如何定义及使用类:
- 如何定义实例属性/方法:
// 定义类
class Person {// 实例属性,方便一眼确认有哪些namefood// 构造方法,类似于构造函数,new的时候会调用,内部的this就是实例化的对象constructor(name, food) {this.name = namethis.food = food}// 实例方法sayHi() {console.log(`你好,我叫${this.name},我喜欢吃${this.food}`)}
}
const p = new Person('小黑', '西蓝花')
p.sayHi()
面试回答:
class核心语法:
- 通过
class 类名{}
的形式来定义类 - 内部直接写实例属性,可以设置默认值,
- 实例方法的添加方式为
方法名(){}
- 构造函数通过
constructor
进行添加 - 通过
new 类名()
创建实例,会调用构造函数constructor
class Person{namefood='西兰花炒蛋'constructor(name){this.name=name}sayHi(){console.log('你好,我叫:',this.name)}
}
class实现继承
关键语法:
- 子类通过extends继承父类
- 子类构造函数中通过super调用父类构造函数
// 在上一份代码的基础上继续编写下面代码
class Student extends Person {songconstructor(name, food, song) {// 子类构造函数使用this以前必须调用supersuper(name, food)this.song = song}// 添加方法sing() {console.log(`我叫${this.name},我喜欢唱${this.song}`)}
}
const s = new Student('李雷', '花菜', '孤勇者')
s.sayHi()
s.sing()
面试回答:
class实现继承
- 子类通过
extends
继承继承父类 - 子类如果需要重新定义构造函数,必须在内部通过
super
关键字调用父类的构造函数
class私有,静态属性和方法
补充语法:
- 私有属性/方法的定义及使用(内部调用)
- 静态属性/方法的定义及使用(类直接访问)
class Person {constructor(name) {this.name = name}// 通过#作为前缀添加的属性会变为私有// 私有属性#secret = '我有一个小秘密,就不告诉你'// 私有方法#say() {// 私有属性可以在console.log('私有的say方法')}info() {// 在类的内部可以访问私有属性调用私有方法console.log(this.#secret)this.#say()}// 通过 static定义静态属性/方法static staticMethod() {console.log('这是一个静态方法')console.log(this)}static info = '直立行走,双手双脚'
}const p = new Person('jack')
console.log(p)
// 外部无法访问 点语法访问直接报错,通过[]无法动态获取
console.log(p['#secret'])
p.info()
// 通过类访问静态属性/方法
Person.staticMethod()
console.log(Person.info)
面试回答:
class语法补充
-
class中私有属性/方法
- 定义和使用时需要使用关键字
#
- 私有属性只能在类的内部使用,外部无法使用(代码中)
- Chrome的控制台中为了方便调试,可以直接访问
- 定义和使用时需要使用关键字
-
class中静态属性/方法
- 定义和使用时需要使用关键字
static
- 通过类访问
- 静态方法中的
this
是类
- 定义和使用时需要使用关键字
fetch
这一节咱们来学习内置函数
fetch
传送门-fetch
传送门-Response
传送门-Headers
ajax&axios&fetch的关系:
ajax
:ajax
是一种基于原生 JavaScript 的异步请求技术。它使用 XMLHttpRequest
对象来发送请求和接收响应。
axios
:axios
是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 中使用。它提供了更高级别的封装,使发送请求和处理响应更加简单和灵活。
fetch
:fetch
是浏览器内置的 API,用于发送网络请求。它提供了一种现代化、基于 Promise 的方式来进行网络通信。用法和axios
类似,但相比于 axios
,它的功能和封装级别更为简单。
全局的fetch
函数用来发起获取资源请求.他返回一个promise
,这个promise
会在请求响应后被resolve
,并传回Response对象
这一节咱们会学习的有:
-
fetch
核心语法 -
fetch
结合URLSearchParams
发送get请求:-
const obj = {name:'jack',age:18 } name=jack&age=17
-
-
fetch
发送post请求,提交FormData
数据 -
fetch
发送post请求,提交JSON
数据
fetch核心语法
核心语法:
- 如何发请求:
- 如何处理响应:
- 注:测试用接口
fetch(资源地址,{...配置项对象})
.then(response=>{// 接收请求
})
面试回答:
fetch核心语法
fetch
函数的参数:- 参数1:请求的url地址
- 参数2:以对象的形式设置请求相关的内容比如,方法,请求头,提交的数据等.
fetch
获取到响应结果,需要如何解析:
fetch(参数1,参数2)
.then(response=>{// 接收请求
})
fetch结合URLSearchParams发送get请求:
需求:
- 使用
fetch
结合URLSearchParams
调用地区查询接口
;(async function () {const params = new URLSearchParams({pname: '广东省',cname: '广州市'})const url = `http://hmajax.itheima.net/api/area?${params.toString()}`// fetch函数返回的是 Promise对象,通过await等待获取response对象const res = await fetch(url)// .json方法返回的是Promise对象 继续通过await等待const data = await res.json()
})()
面试回答:
fetch结合URLSearchParams发送get请求:
fetch
发送get请求时,不需要设置请求方法,因为默认的就是get
URLSearchParams
可以用来创建或者解析查询字符串,这里通过它将对象转为查询字符串
post请求-提交JSON
需求:
fetch
发送post请求,提交JSON
数据- 测试接口-用户注册
核心步骤:
- 根据文档设置请求头
- 通过配置项设置,请求方法,请求头,请求体
; (async function () {// 通过headers设置请求头const headers = new Headers()// 通过 content-type指定请求体数据格式headers.append('content-type', 'application/json')// 参数1 url// 参数2 请求配置const res = await fetch('http://hmajax.itheima.net/api/register', {method: 'post',// 请求方法headers, // 请求头// 请求体body: JSON.stringify({ username: 'itheima9876', password: '123456' })})const json = await res.json()console.log(json)})()
面试回答:
post请求-提交JSON
fetch
函数的第二个参数可以设置请求头,请求方法,请求体,根据接口文档设置对应的内容即可- 可以通过
JSON.stringify
将对象转为JSON
post请求-提交FormData
需求:
fetch
发送post请求,提交FormData
数据(上传+回显)- 测试接口-上传图片
核心步骤:
- 通过
FormData
添加文件 - 通过配置项设置,请求方法,请求体(
FormData
不需要设置请求头)
<input type="file" class="file" accept="image/*"><script>document.querySelector('.file').addEventListener('change', async function (e) {// 生成FormData对象并添加数据const data = new FormData()data.append('img', this.files[0])const res = await fetch('http://hmajax.itheima.net/api/uploadimg', {method: 'post',body: data})const json = await res.json()console.log(json)})</script>
面试回答:
-
post请求-提交FormData
-
fetch
提交FormData
时不需要额外的设置请求头 -
实例化
FormData
之后可以通过append(key,value)
方法来动态添加数据
-
-
ajax&axios&fetch的关系
-
ajax
是一种基于原生JavaScript的异步请求技术,他使用XMLHttpRequest
对象来发送请求和接收响应—学习原理时适用 -
axios
是一个基于Promise的http客户端,可以在浏览器和Node.js中使用.他提供了更高级别的封装,使发送请求和处理响应更加简单和灵活—项目开发时适用 -
fetch
是浏览器内置的API,用于发送网络请求.它基于Promise的方式来进行网络通信.和axios
类似.但是功能和封装级别比axios
更为简单—项目简单,不想导入axios时适用
-
Generator
这一节咱们来学习
generator
传送门-Generator
Generator
对象由生成器函数返回并且它符合可迭代协议和迭代器协议.他可以用来控制流程,语法行为和之前学习的函数不一样
Generator-核心语法
核心语法:
- 如何定义生成器函数:
- 如何获取
generator
对象 yield
表达式的使用- 通过
for of
获取每一个yield
的值
// 1. 通过function* 创建生成器函数
function* foo() {// 遇到yield表达式时会暂停后续的操作yield 'a'yield 'b'yield 'c'return 'd'
}
// 2. 调用函数获取生成器
const f = foo()
// 3. 通过next方法获取yield 之后的表达式结果,会被包装到一个对象中
// 执行一次next 即可获取一次 yield之后的表达式结果
const res1 = f.next()
console.log(res1)// {value: 'a', done: false}
const res2 = f.next()
console.log(res2)// {value: 'b', done: false}
const res3 = f.next()
console.log(res3)// {value: 'c', done: false}
// 最后一次可以拿到return的结果
const res4 = f.next()
console.log(res4)// {value: 'd', done: true}
// done 为true之后,获取到的value为undefined
const res5 = f.next()
console.log(res5)// {value: undefined, done: true} // 4. 通过for of 获取每一个yield之后的值,
const f2 = foo()
for (const iterator of f2) {console.log(iterator)
}
面试回答:
Generator-核心语法
- 可以通过生成器函数(
function* xxx(){}
)来生成Generator
对象: - 通过
Generator
对象的next
方法可以获取yield
表达式之后的结果
Generator-id生成器
**需求:**使用Generator
实现一个id生成器id
function* idGenerator() {// 逻辑略
}
const idMaker = idGenerator()// 调用next方法,获取id(每次累加1)
const { value: id1 } = idMaker.next()
console.log(id1)
const { value: id2 } = idMaker.next()
console.log(id2)
核心步骤:
- 定义生成器函数
- 内部使用循环,通过
yield
返回id
并累加
// 1. 通过function* 创建生成器函数
function* generator() {let id = 0// 无限循环while (true) {// id累加并返回yield id++}
}
// 2. 调用函数获取生成器
const idMaker = generator()
// 3. 需要id的时候 通过next获取即可
const { value: id1 } = idMaker.next()
console.log(id1)
const { value: id2 } = idMaker.next()
console.log(id2)
面试回答:
Generator-id生成器
- 生成器函数内部的代码会在调用
next
方法时执行,利用这一特点,可以实现任意的生成器,需要时调用next
即可获取结果
Generator-流程控制
遇到yield
表达式时会暂停后续的操作
**需求:**使用Generator
实现流程控制
function* weatherGenerator() {// 逻辑略yield axios()
}
// 获取Generator实例
const weather = weatherGenerator()
// 依次获取 北上广深的天气 (axios)
weather.next()
核心步骤:
yield
后面跟上天气查询逻辑- 接口文档-天气预报
- 参考
code
:北京 110100 上海 310100 广州 440100 深圳 440300
<button class="getWeather">天气查询</button><script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.js"></script><script>/*** 需求:流程控制,依次查询,北上广深的天气预报* 参考code: 北京 110100 上海 310100 广州 440100 深圳 440300* 接口文档: https://apifox.com/apidoc/project-1937884/api-49760220* */function* weatherGenerator() {// 北京yield axios('http://hmajax.itheima.net/api/weather?city=110100')// 上海yield axios('http://hmajax.itheima.net/api/weather?city=310100')// 广州yield axios('http://hmajax.itheima.net/api/weather?city=440100')// 深圳yield axios('http://hmajax.itheima.net/api/weather?city=440300')}const cityWeather = weatherGenerator()document.querySelector('.getWeather').addEventListener('click', async () => {const res = await genCity.next()console.log(res)})</script>
面试回答:
Generator-流程控制
- 使用
Generator
控制流程的本质是利用yield
关键字来分隔逻辑比如示例中依次调用了多个接口,通过yield
分隔,通过next
来触发调用
参考资料
- 阮一峰-《ECMAScript 6 教程》
- 图灵社区-JavaScript高级程序设计
相关文章:
JS原理-笔记(1/3)
JS原理-笔记(1/3) 知识点自测 今天课程中涉及到的已学习知识点 函数的call方法-文档链接 // 以指定的this调用函数,并通过 从第二个参数开始依次传递参数 function func(food,drink){console.log(this)console.log(food)console.log(drink)…...

Django创建应用、ORM的进阶使用及模型类数据库迁移
1 Django项目创建第一个应用 Django 项目就是基于 Django 框架开发的 Web 应用,它包含了一组配置和多个应用,我们把应用称之为 App,在前文中对它也做了相应的介绍,比如 auth、admin,它们都属于 APP。 一个 App 就是一…...
tcpdump 如何使用
tcpdump 是一个在Unix和类Unix系统上运行的网络抓包工具,它用于捕获网络流量并将其转储到文件中以供后续分析。tcpdump非常强大,可以用于监控、调试和分析网络通信,用于排查网络问题以及安全审计。以下是关于如何使用tcpdump的详细介绍&#…...

goweb入门
创建gomod项目 go mod init web01新建main.go package mainimport ("fmt""net/http" )func handler(writer http.ResponseWriter, request *http.Request) {fmt.Fprintf(writer, "Hello World,%s!", request.URL.Path[1:]) } func main() {fmt…...
【python爬虫】批量识别pdf中的英文,自动翻译成中文下
不管是上学还是上班,有时不可避免需要看英文文章,特别是在写毕业论文的时候。比较头疼的是把专业性很强的英文pdf文章翻译成中文。我记得我上学的时候,是一段一段复制,或者碰到不认识的单词就百度翻译一下,非常耗费时间。之前的文章提供了批量识别pdf中英文的方法,详见【…...

YApi 新版如何查看 http 请求数据
YApi 新版如何查看 http 请求数据 因chrome 安全策略限制,在 cross-request 升级到 3.0 后, 不再支持文件上传功能,并且需要通过以下方法查看 network:1.首先在chrome 输入 > chrome://extensions打开扩展页2.开启开发者模式3.点击 cross…...

自动驾驶(apollo)
💓博主csdn个人主页:小小unicorn 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 自动驾驶技术 引言自动驾驶的基本原理自动驾驶的技术挑战自动驾驶的潜在影响结…...
web3.0涉及的技术
非同质化代币 非同质化代币(Non-Fungible Tokens,NFTs)是一种数字资产,与传统的加密货币(如比特币或以太币)不同,它们具有独特性和不可替代性。NFTs 是基于区块链技术的数字资产,用…...

26. 不相同的字符串(第一期模拟笔试)
题目:样例: 输入 1 abab 输出 2 思路: 这里的题目要求我们要最少操作删除次数,我们可以先统计每个字符个数,然后开始删除,每操作删除一次,就会产生一个新字符,ans r[i] >> 1…...

Rethink LSTMGRU
LSTM 设计思想 姑且不看偏置。 W W W 和 U U U 是加权的矩阵,写模型的时候用 nn.Linear(in_dim, out_dim) 就成; σ \sigma σ 是 Sigmoid 函数 第一条,遗忘门,定义为 有多少内容需要被遗忘;第二条:输入门…...

状态管理艺术——借助Spring StateMachine驭服复杂应用逻辑
文章目录 1. 什么是状态2. 有限状态机概述3. Spring StateMachine4. Spring StateMachine 入门小案例4.1 接口测试 5. 总结 1. 什么是状态 在开发中,无时无刻离不开状态的一个概念,任何一条数据都有属于它的状态。 比如一个电商平台,一个订…...
获取和设置小程序和h5的页面栈
获取页面栈: 语法: let pages getCurrentPages(); 设置页面栈: 小程序语法: pages.data H5语法: pages let pages getCurrentPages(); let page pages[pages.length - 2]; if(page.route "pages/conf…...

Mysql基于成本选择索引
本篇文章介绍mysql基于成本选择索引的行为,解释为什么有时候明明可以走索引,但mysql却没有走索引的原因 mysql索引失效的场景大致有几种 不符合最左前缀原则在索引列上使用函数或隐式类型转换使用like查询,如 %xxx回表代价太大索引列区分度过…...

Element-ui container常见布局
1、header\main布局 <template> <div> <el-container> <el-header>Header</el-header> <el-main>Main</el-main> </el-container> </div> </template> <style> .el-header { …...

ssm实现折线统计图
方法1:单张数据表中的数据图表生成 图表统计,查看部门人数统计这里实现的时单张表中的数据实现部门人数折线统计图展示。 <script type"text/javascript">// 利用AjAx来获取后台传入的数据(Responsebody注解传入的&…...

GLSL ES着色器 精度限定字
目录 前言 WebGL支持的三种精度 数据类型的默认精度 float类型没有默认精度 预处理指令 在GLSL ES中常用的三种预处理指令。 预定义的内置宏 前言 GLSL ES新引入了精度限定字,目的是帮助着色器程序提高运行效率,削减内存开支。顾名思义…...

webrtc的FULL ICE和Lite ICE
1、ICE的模式 分为FULL ICE和Lite ICE: FULL ICE:是双方都要进行连通性检查,完成的走一遍流程。 Lite ICE: 在FULL ICE和Lite ICE互通时,只需要FULL ICE一方进行连通性检查, Lite一方只需回应response消息。这种模式对于部署在公网…...

flink的几种常见的执行模式
背景 在运行flink时,我们经常会有几种不同的执行模式,比如在IDE中启动时,通过提交到YARN上,还有通过Kebernates启动时,本文就来记录一下这几种模式 flink的几种执行模式 flink嵌入式模式: 这是一种我们在…...

蓝桥杯备赛Day8——队列
大家好,我是牛哥带你学代码,本专栏详细介绍了蓝桥杯备赛的指南,特别适合迎战python组的小白选手。专栏以天作为单位,定期更新,将会一直更新,直到所有数据结构相关知识及高阶用法全部囊括,欢迎大家订阅本专栏! 队列也属于基础数据结构。 队列概念 队列是一种数据结构,…...

用滑动条做调色板---cv2.getTrackbarPos(),cv2.creatTrackbar()
滑动轨迹栏作调色板 cv.createTrackbar(‘R’, ‘image’, 0, 255, nothing) 参数:哪个滑动轨迹栏,哪个窗口,最小值,最大值,回调函数 cv.getTrackbarPos(‘R’, ‘image’) 参数:轨迹栏名,窗口…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...