知识点自测
今天课程中涉及到的已学习知识点
函数的call方法-文档链接
1 2 3 4 5 6 7 8 9 10
| function func(food,drink){ console.log(this) console.log(food) console.log(drink) } const obj = { name:'小黑' } func.call(obj,'西蓝花','咖啡')
|
函数的apply方法-文档链接
1 2 3 4 5 6 7 8 9 10
| function func(food,drink){ console.log(this) console.log(food) console.log(drink) } const obj = { name:'小黑' } func.apply(obj,['西蓝花','咖啡'])
|
函数的bind方法-文档链接
1 2 3 4 5 6 7 8 9 10
| function func(food, drink) { console.log(this) console.log(food) console.log(drink) } const obj = { name: '小黑' } const bindFunc = func.bind(obj, '花菜') bindFunc('可乐')
|
1 2 3 4
| function func(...args){ console.log(args) } func('西蓝花','西葫芦','西洋参','西芹')
|
Promise核心用法-文档链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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核心用法-文档链接
1 2 3 4
| const params = new URLSearchParams({ name: 'jack', age: 18 })
console.log(params.toString())
|
Object.create核心用法-文档链接
1 2 3 4 5 6 7 8 9
| const person = { name: 'itheima', foods: ['西蓝花', '西红柿', '西葫芦'] }
const clone = Object.create(person) clone.name = 'itheima' clone.foods.push('西北风') console.log(clone.foods === person.foods)
|
Object.assign核心用法-文档链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const person = { name: 'itheima', foods: ['西蓝花', '西红柿', '西葫芦'] } const son = { name: 'rose', }
const returnTarget = Object.assign(son, person)
console.log(returnTarget === son) console.log(son.name) console.log(son.foods === person.foods)
|
JS中的this
这一节咱们来学习JS中this相关的知识点
传送门:MDN-this
传送门:MDN-call
传送门:MDN-apply
传送门:MDN-bind
传送门:MDN-箭头函数
传送门:MDN-剩余参数
传送门:MDN-Symbol
这一节咱们会学习的有:
- 如何确认
this指向
- 如何改变
this指向
- 手写
call,apply,bind
如何确认this的值:
在非严格模式下,总是指向一个对象,在严格模式下可以是任意值,开启严格模式可以使用如下两种方式:
- 在整个脚本顶部开启
- 在函数顶部开启
1 2 3 4 5 6
| 'use strict' function func() { 'use strict' }
|
然后就可以根据不同的模式来确认this指向啦,
全局执行环境中,指向全局对象(非严格模式、严格模式)
函数内部,取决于函数被调用的方式
直接调用的this值:
- 非严格模式:全局对象(window)
- 严格模式:undefined
对象方法调用的this值:
- 调用者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
|
面试回答:
如何确认this指向:
全局执行环境中,指向全局对象(非严格模式、严格模式)
如何开启严格模式:
1 2 3 4 5 6
| 'use strict' function func() { 'use strict' }
|
函数内部,取决于函数被调用的方式
直接调用的this值:
- 非严格模式:全局对象(window)
- 严格模式:undefined
对象方法调用时的this值为调用者
如何改变this指向
主要有2类改变函数内部this指向的方法:
调用函数并传入具体的this:
call:
- 参数1:
this
- 参数2-n:传递给函数的参数
apply-数组作为参数
- 参数1:
this
- 参数2:以数组的形式,传递给函数的参数
创建绑定this的函数:
- bind:返回一个绑定了
this的新函数
- 箭头函数:最近的this是谁,就是谁
调用函数并传入具体的this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function funcA(p1, p2) { console.log('funcA-调用') console.log(this) console.log('p1:', p1) console.log('p2:', p2) } const obj = { name: 'jack' }
funcA.call(obj, 1, 2)
funcA.apply(obj, [3, 4])
|
创建绑定this的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function funcB(p1, p2) { console.log('funcB-调用') console.log(this) console.log('p1:', p1) console.log('p2:', p2) } const person = { name: 'itheima' }
const bindFuncB = funcB.bind(person, 123) bindFuncB(666)
const student = { name: 'lilei', sayHi: function () { console.log(this) const inner = () => { console.log('inner-调用了') console.log(this) } inner() } } student.sayHi()
|
面试回答:
如何改变this指向,有2类改变this指向的方法,分别是:
调用函数时并传入具体的this
call:从第二个参数开始挨个传递参数
apply:在第二个参数以数组的形式传递参数
创建函数时绑定this?
bind:返回一个绑定了this以及参数(可选)的新函数
箭头函数:创建时会绑定上一级作用域中的this
手写call方法
这一节咱们来实现myCall方法,实际用法和call方法一致,核心步骤有4步
1 2 3 4 5 6 7 8 9 10 11 12 13
| const person = { name: 'itheima' } function func(numA, numB) { console.log(this) console.log(numA, numB) return numA + numB }
const res = func.myCall(person, 2, 8) console.log('返回值为:', res)
|
- 如何定义
myCall?
- 如何让函数内部的
this为某个对象?
- 如何让
myCall接收参数2-参数n?
- 使用Symbol调优
myCall?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| Function.prototype.myCall = function () { }
Function.prototype.myCall = function (thisArg) { thisArg['fn'] = this const res = thisArg['fn']() delete thisArg['fn']
}
Function.prototype.myCall = function (thisArg, ...args) { thisArg['fn'] = this const res = thisArg['fn'](...args) delete thisArg['fn'] return res }
Function.prototype.myCall = function (thisArg, ...args) { const fn = Symbol() thisArg[fn] = this 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.myCall(person, 2, 8) console.log('返回值为:', res)
|
面试回答:
手写call方法的步骤为
- 在
function的原型上添加myCall方法,保证所有函数都可以调用
- 方法内部,通过动态为对象添加方法的形式来指定
this指向
- 调用完毕之后通过
delete关键字删除上一步动态增加的方法
- 方法的名字通过Symbol进行设置,避免和默认名重复
- 使用剩余参数的形式传递参数2-参数n(函数参数)
1 2 3 4 5 6 7
| Function.prototype.myCall = function (thisArg, ...args) { const fn = Symbol() thisArg[fn] = this const res = thisArg[fn](...args) delete thisArg[fn] return res }
|
手写apply方法
这一节咱们来实现myApply方法,实际用法和apply方法一致,核心步骤依旧4步
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Function.prototype.myApply = function () { }
Function.prototype.myApply = function (thisArg) { const fn = Symbol() thisArg[fn] = this const res = thisArg[fn](...args) delete thisArg[fn] return res }
Function.prototype.myApply = function (thisArg, args) { const fn = Symbol() thisArg[fn] = this 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进行设置,避免和默认名重复
- 直接使用数组传递函数的参数,内部调用时结合
...运算符展开数组
1 2 3 4 5 6 7
| Function.prototype.myApply = function (thisArg, args) { const fn = Symbol() thisArg[fn] = this const res = thisArg[fn](...args) delete thisArg[fn] return res }
|
手写bind方法
这一节咱们来实现myBind方法,实际用法和bind方法一致,核心步骤为2步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| Function.prototype.myBind = function (thisArg) { return () => { this.call(thisArg) } }
Function.prototype.myBind = function (thisArg, ...args) { return (...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指定绑定的参数,和调用时传递的参数
1 2 3 4 5
| 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高级程序设计》)
- 原型链实现继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
1 2 3 4 5 6 7 8
| function Parent(){ this.name = name this.foods = ['西蓝花', '西红柿'] this.sayFoods = function () { console.log(this.foods) } }
|
ES5-原型链实现继承
核心步骤:希望继承谁,就将谁作为原型
缺点:父类中的引用数据类型,会被所有子类共享
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function Parent(name) { this.name = name this.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父类的构造函数
缺点:子类没法使用父类原型上的属性/方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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次构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function Person(name) { this.name = name }
Person.prototype.sayHi = function () { console.log(`你好,我叫${this.name}`) }
function Student(name, age) { Person.call(this, name) this.age = age }
Student.prototype = new Person()
const s = new Student('李雷', 18)
|
面试回答:
ES5-组合继承
组合继承的核心步骤有2步:
- 通过原型链继承公共的属性和方法
- 通过构造函数继承实例独有的属性和方法
组合继承的特点:调用2次父类的构造函数,浪费性能
ES5-原型式继承
直接基于对象实现继承
核心步骤:对某个对象进行浅拷贝(工厂函数或Object.create),实现继承
缺点:父类中的引用数据类型,会被所有子类共享
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function objectFactory(obj) { function Fun() { } Fun.prototype = obj return 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-寄生式继承
核心步骤:
定义工厂函数,并在内部:
- 对传入的对象进行浅拷贝(公共属性/方法)
- 为浅拷贝对象增加属性/方法(独有属性/方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function createAnother(origin) { 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-寄生组合式继承
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型 原型的一个副本而已。
核心步骤:
- 通过构造函数来继承属性
- 通过原型链来继承方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function inheritPrototype(son, parent){ const prototype = object.create(parent.prototype) prototype.constructor = son son.prototype = prototype }
function Parent(name) { this.name = name this.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核心语法
核心语法:
- 如何定义及使用类:
- 如何定义实例属性/方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person { name food constructor(name, food) { this.name = name this.food = food }
sayHi() { console.log(`你好,我叫${this.name},我喜欢吃${this.food}`) } } const p = new Person('小黑', '西蓝花') p.sayHi()
|
面试回答:
class核心语法:
- 通过
class 类名{}的形式来定义类
- 内部直接写实例属性,可以设置默认值,
- 实例方法的添加方式为
方法名(){}
- 构造函数通过
constructor进行添加
- 通过
new 类名()创建实例,会调用构造函数constructor
1 2 3 4 5 6 7 8 9 10 11
| class Person{ name food='西兰花炒蛋' constructor(name){ this.name=name } sayHi(){ console.log('你好,我叫:',this.name) } }
|
class实现继承
关键语法:
- 子类通过extends继承父类
- 子类构造函数中通过super调用父类构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Student extends Person { song constructor(name, food, song) { super(name, food) this.song = song } sing() { console.log(`我叫${this.name},我喜欢唱${this.song}`) } } const s = new Student('李雷', '花菜', '孤勇者') s.sayHi() s.sing()
|
面试回答:
class实现继承
- 子类通过
extends继承继承父类
- 子类如果需要重新定义构造函数,必须在内部通过
super关键字调用父类的构造函数
class私有,静态属性和方法
补充语法:
- 私有属性/方法的定义及使用(内部调用)
- 静态属性/方法的定义及使用(类直接访问)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Person { constructor(name) { this.name = name } #secret = '我有一个小秘密,就不告诉你' #say() { console.log('私有的say方法') } info() { console.log(this.#secret) this.#say() }
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请求:
- ```javascript
const obj = {name:'jack',
age:18
}
name=jack&age=171 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 3. `fetch`发送post请求,提交`FormData`数据
4. `fetch`发送post请求,提交`JSON`数据
### fetch核心语法
**核心语法:**
1. 如何[发请求](https://developer.mozilla.org/zh-CN/docs/Web/API/fetch): 2. 如何处理[响应](https://developer.mozilla.org/zh-CN/docs/Web/API/Response): 3. 注:[测试用接口](https://apifox.com/apidoc/project-1937884/api-49760223)
```javascript fetch(资源地址,{...配置项对象}) .then(response=>{ // 接收请求 })
|
面试回答:
fetch核心语法
fetch函数的参数:
- 参数1:请求的url地址
- 参数2:以对象的形式设置请求相关的内容比如,方法,请求头,提交的数据等.
fetch获取到响应结果,需要如何解析:
1 2 3 4
| fetch(参数1,参数2) .then(response=>{ })
|
fetch结合URLSearchParams发送get请求:
需求:
- 使用
fetch结合URLSearchParams调用地区查询接口
1 2 3 4 5 6 7 8 9 10 11
| ;(async function () { const params = new URLSearchParams({ pname: '广东省', cname: '广州市' }) const url = `http://hmajax.itheima.net/api/area?${params.toString()}` const res = await fetch(url) const data = await res.json() })()
|
面试回答:
fetch结合URLSearchParams发送get请求:
fetch发送get请求时,不需要设置请求方法,因为默认的就是get
URLSearchParams可以用来创建或者解析查询字符串,这里通过它将对象转为查询字符串
post请求-提交JSON
需求:
fetch发送post请求,提交JSON数据
- 测试接口-用户注册
核心步骤:
- 根据文档设置请求头
- 通过配置项设置,请求方法,请求头,请求体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ; (async function () { const headers = new Headers() headers.append('content-type', 'application/json') 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不需要设置请求头)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <input type="file" class="file" accept="image/*"> <script> document.querySelector('.file').addEventListener('change', async function (e) { 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function* foo() { yield 'a' yield 'b' yield 'c' return 'd' }
const f = foo()
const res1 = f.next() console.log(res1) const res2 = f.next() console.log(res2) const res3 = f.next() console.log(res3)
const res4 = f.next() console.log(res4)
const res5 = f.next() console.log(res5)
const f2 = foo() for (const iterator of f2) { console.log(iterator) }
|
面试回答:
Generator-核心语法
- 可以通过生成器函数(
function* xxx(){})来生成Generator对象:
- 通过
Generator对象的next方法可以获取yield表达式之后的结果
Generator-id生成器
需求:使用Generator实现一个id生成器id
1 2 3 4 5 6 7 8 9 10
| function* idGenerator() { } const idMaker = idGenerator()
const { value: id1 } = idMaker.next() console.log(id1) const { value: id2 } = idMaker.next() console.log(id2)
|
核心步骤:
- 定义生成器函数
- 内部使用循环,通过
yield返回id并累加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function* generator() { let id = 0 while (true) { yield id++ } }
const idMaker = generator()
const { value: id1 } = idMaker.next() console.log(id1) const { value: id2 } = idMaker.next() console.log(id2)
|
面试回答:
Generator-id生成器
- 生成器函数内部的代码会在调用
next方法时执行,利用这一特点,可以实现任意的生成器,需要时调用next即可获取结果
Generator-流程控制
遇到yield表达式时会暂停后续的操作
需求:使用Generator实现流程控制
1 2 3 4 5 6 7 8
| function* weatherGenerator() { yield axios() }
const weather = weatherGenerator()
weather.next()
|
核心步骤:
yield后面跟上天气查询逻辑
- 接口文档-天气预报
- 参考
code:北京 110100 上海 310100 广州 440100 深圳 440300
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <button class="getWeather">天气查询</button> <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.js"></script> <script>
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高级程序设计