当前位置: 首页 > news >正文

JS原理-笔记(1/3)

JS原理-笔记(1/3)

知识点自测

今天课程中涉及到的已学习知识点

  1. 函数的call方法-文档链接
// 以指定的this调用函数,并通过 从第二个参数开始依次传递参数
function func(food,drink){console.log(this)console.log(food)console.log(drink)
}
const obj = {name:'小黑'
}
func.call(obj,'西蓝花','咖啡')
  1. 函数的apply方法-文档链接
// 以指定的this调用函数,并通过 数组的形式 传递参数
function func(food,drink){console.log(this)console.log(food)console.log(drink)
}
const obj = {name:'小黑'
}
func.apply(obj,['西蓝花','咖啡'])
  1. 函数的bind方法-文档链接
function func(food, drink) {console.log(this)console.log(food)console.log(drink)
}
const obj = {name: '小黑'
}
const bindFunc = func.bind(obj, '花菜')
bindFunc('可乐')
  1. 剩余参数-文档链接
function func(...args){console.log(args)// 以数组的形式获取传入的所有参数
}
func('西蓝花','西葫芦','西洋参','西芹')
  1. 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)
})
  1. URLSearchParams核心用法-文档链接
// 实例化时支持传入JS对象
const params = new URLSearchParams({ name: 'jack', age: 18 })
// toString方法 返回搜索参数组成的字符串,可直接使用在 URL 上。
console.log(params.toString())
  1. 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
  1. 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

这一节咱们会学习的有:

  1. 如何确认this指向
  2. 如何改变this指向
  3. 手写callapplybind

如何确认this的值:

在非严格模式下,总是指向一个对象,在严格模式下可以是任意值,开启严格模式可以使用如下两种方式:

  1. 在整个脚本顶部开启
  2. 在函数顶部开启
// 为整个脚本开启严格模式
'use strict'
function func() {// 为函数开启严格模式'use strict'
}

然后就可以根据不同的模式来确认this指向啦,

  1. 全局执行环境中,指向全局对象(非严格模式、严格模式)

  2. 函数内部,取决于函数被调用的方式

    1. 直接调用的this值:

      1. 非严格模式:全局对象(window)
      2. 严格模式:undefined
    2. 对象方法调用的this值:

      1. 调用者
// 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指向:

  1. 全局执行环境中,指向全局对象(非严格模式、严格模式)

  2. 如何开启严格模式:

    // 为整个脚本开启严格模式
    'use strict'
    function func() {// 为函数开启严格模式'use strict'
    }
    
  3. 函数内部,取决于函数被调用的方式

    1. 直接调用的this值:

      1. 非严格模式:全局对象(window)
      2. 严格模式:undefined
    2. 对象方法调用时的this值为调用者

如何改变this指向

主要有2类改变函数内部this指向的方法:

  1. 调用函数并传入具体的this:

    1. call:

      1. 参数1:this
      2. 参数2-n:传递给函数的参数
    2. apply-数组作为参数

      1. 参数1:this
      2. 参数2:以数组的形式,传递给函数的参数
  2. 创建绑定this的函数:

    1. bind:返回一个绑定了this的新函数
    2. 箭头函数:最近的this是谁,就是谁

调用函数并传入具体的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指向的方法,分别是:

  1. 调用函数时并传入具体的this

    1. call:从第二个参数开始挨个传递参数

    2. apply:在第二个参数以数组的形式传递参数

  2. 创建函数时绑定this?

    1. bind:返回一个绑定了this以及参数(可选)的新函数

    2. 箭头函数:创建时会绑定上一级作用域中的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)
  1. 如何定义myCall?
  2. 如何让函数内部的this为某个对象?
  3. 如何让myCall接收参数2-参数n?
  4. 使用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方法的步骤为

  1. function的原型上添加myCall方法,保证所有函数都可以调用
  2. 方法内部,通过动态为对象添加方法的形式来指定this指向
  3. 调用完毕之后通过delete关键字删除上一步动态增加的方法
  4. 方法的名字通过Symbol进行设置,避免和默认名重复
  5. 使用剩余参数的形式传递参数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)
  1. 如何定义myApply?

    1. 定义在原型上
  2. 如何让函数内部的this为某个对象?

    1. 动态给对象添加方法,通过对象.方法()调用即可
    2. 使用Symbol来生成方法名
  3. 如何让myApply接收参数?

    1. 定义参数2即可
    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方法

  1. function的原型上添加myApply方法,保证所有函数都可以调用
  2. 方法内部,通过动态为对象添加方法的形式来指定this指向
  3. 调用完毕之后通过delete关键字删除上一步动态增加的方法
  4. 方法的名字通过Symbol进行设置,避免和默认名重复
  5. 直接使用数组传递函数的参数,内部调用时结合...运算符展开数组
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)
  1. 如何返回一个绑定了this的函数?
  2. 如何实现绑定的参数,及传入的参数合并?
// 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方法

  1. function原型上添加myBind函数,参数1为绑定的this,参数2-参数2为绑定的参数
  2. 内部返回一个新箭头函数,目的是绑定作用域中的this
  3. 返回的函数内部,通过call进行this和参数绑定
  4. 通过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高级程序设计》)

  1. 原型链实现继承
  2. 构造函数继承
  3. 组合继承
  4. 原型式继承
  5. 寄生式继承
  6. 寄生组合式继承
// 父类
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-原型链实现继承

  1. 将父类的实例作为子类的原型实现继承
  2. 这种继承方法的缺点是父类中的引用类型数据会被所有子类共享

ES5-构造函数继承

**核心步骤:**在子类的构造函数中通过callapply父类的构造函数

**缺点:**子类没法使用父类原型上的属性/方法

// 父类
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-构造函数继承

  1. 在子类的构造函数中通过call或者apply调用父类的构造函数
  2. 这种继承方法的缺点是:子类没法使用父类原型上的属性/方法

ES5-组合继承

通过组合继承,结合上面2种方法的优点

核心步骤:

  1. 通过原型链继承公共的属性和方法
  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-组合继承

  1. 组合继承的核心步骤有2步:

    1. 通过原型链继承公共的属性和方法
    2. 通过构造函数继承实例独有的属性和方法
  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-原型式继承

  1. 原型式继承的核心步骤是:对某个对象进行浅拷贝,可以通过内置apiObject.create实现,不需要调用构造函数即可实现继承,主要针对于继承对象的情况
  2. 原型式继承的缺点是:父类中的引用数据类型,会被所有子类共享

ES5-寄生式继承

核心步骤:

定义工厂函数,并在内部:

  1. 对传入的对象进行浅拷贝(公共属性/方法)
  2. 为浅拷贝对象增加属性/方法(独有属性/方法)
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)

面试回答:

寄生式继承

  1. 寄生式继承的核心步骤是:基于对象创建新对象(可以使用Object.create),并且为新创建的对象增加新的属性和方法

  2. 寄生式继承和上一节学习的原型式继承的区别是:创建出来的新对象,会额外的增加新的属性/方法

ES5-寄生组合式继承

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型 原型的一个副本而已。

核心步骤:

  1. 通过构造函数来继承属性
  2. 通过原型链来继承方法
// 继承原型函数
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-寄生组合式继承

  1. 寄生组合式继承的核心步骤是:通过构造函数来继承属性,通过原型链来继承方法
  2. 寄生组合式继承和组合式继承的区别是:原型链的继承并没有调用父类的构造函数,而是直接基于父类的原型创建一个新副本实现继承

JS继承-ES6

这一节咱们来学习在ES6中class关键字的使用,并且使用它来实现继承

传送门:mdn类

传送门:阮一峰ES6-class

传送门:mdn-super

ES6中推出了class类,是用来创建对象的模板.class可以看作是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

这一节咱们会学习:

  1. class核心语法
  2. class实现继承
  3. class语法补充

class核心语法

核心语法:

  1. 如何定义及使用类:
  2. 如何定义实例属性/方法:
// 定义类
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核心语法:

  1. 通过class 类名{}的形式来定义类
  2. 内部直接写实例属性,可以设置默认值,
  3. 实例方法的添加方式为方法名(){}
  4. 构造函数通过constructor进行添加
  5. 通过new 类名()创建实例,会调用构造函数constructor
class Person{namefood='西兰花炒蛋'constructor(name){this.name=name}sayHi(){console.log('你好,我叫:',this.name)}
}

class实现继承

关键语法:

  1. 子类通过extends继承父类
  2. 子类构造函数中通过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实现继承

  1. 子类通过extends继承继承父类
  2. 子类如果需要重新定义构造函数,必须在内部通过super关键字调用父类的构造函数

class私有,静态属性和方法

补充语法:

  1. 私有属性/方法的定义及使用(内部调用)
  2. 静态属性/方法的定义及使用(类直接访问)
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语法补充

  1. class中私有属性/方法

    1. 定义和使用时需要使用关键字#
    2. 私有属性只能在类的内部使用,外部无法使用(代码中)
    3. Chrome的控制台中为了方便调试,可以直接访问
  2. class中静态属性/方法

    1. 定义和使用时需要使用关键字static
    2. 通过类访问
    3. 静态方法中的this是类

fetch

这一节咱们来学习内置函数fetch

传送门-fetch

传送门-Response

传送门-Headers

ajax&axios&fetch的关系:

ajaxajax 是一种基于原生 JavaScript 的异步请求技术。它使用 XMLHttpRequest 对象来发送请求和接收响应。

axiosaxios 是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 中使用。它提供了更高级别的封装,使发送请求和处理响应更加简单和灵活。

fetchfetch 是浏览器内置的 API,用于发送网络请求。它提供了一种现代化、基于 Promise 的方式来进行网络通信。用法和axios类似,但相比于 axios,它的功能和封装级别更为简单。

全局的fetch函数用来发起获取资源请求.他返回一个promise,这个promise会在请求响应后被resolve,并传回Response对象

这一节咱们会学习的有:

  1. fetch核心语法

  2. fetch结合URLSearchParams发送get请求:

    1. const obj = {name:'jack',age:18
      }
      name=jack&age=17
      
  3. fetch发送post请求,提交FormData数据

  4. fetch发送post请求,提交JSON数据

fetch核心语法

核心语法:

  1. 如何发请求:
  2. 如何处理响应:
  3. 注:测试用接口
fetch(资源地址,{...配置项对象})
.then(response=>{// 接收请求
})

面试回答:

fetch核心语法

  1. fetch函数的参数:
    1. 参数1:请求的url地址
    2. 参数2:以对象的形式设置请求相关的内容比如,方法,请求头,提交的数据等.
  2. fetch获取到响应结果,需要如何解析:
fetch(参数1,参数2)
.then(response=>{// 接收请求
})

fetch结合URLSearchParams发送get请求:

需求:

  1. 使用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请求:

  1. fetch发送get请求时,不需要设置请求方法,因为默认的就是get
  2. URLSearchParams可以用来创建或者解析查询字符串,这里通过它将对象转为查询字符串

post请求-提交JSON

需求:

  1. fetch发送post请求,提交JSON数据
  2. 测试接口-用户注册

核心步骤:

  1. 根据文档设置请求头
  2. 通过配置项设置,请求方法,请求头,请求体
    ; (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

  1. fetch函数的第二个参数可以设置请求头,请求方法,请求体,根据接口文档设置对应的内容即可
  2. 可以通过JSON.stringify将对象转为JSON

post请求-提交FormData

需求:

  1. fetch发送post请求,提交FormData数据(上传+回显)
  2. 测试接口-上传图片

核心步骤:

  1. 通过FormData添加文件
  2. 通过配置项设置,请求方法,请求体(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>

面试回答:

  1. post请求-提交FormData

    1. fetch提交FormData时不需要额外的设置请求头

    2. 实例化FormData之后可以通过append(key,value)方法来动态添加数据

  2. ajax&axios&fetch的关系

    1. ajax是一种基于原生JavaScript的异步请求技术,他使用XMLHttpRequest对象来发送请求和接收响应—学习原理时适用

    2. axios是一个基于Promise的http客户端,可以在浏览器和Node.js中使用.他提供了更高级别的封装,使发送请求和处理响应更加简单和灵活—项目开发时适用

    3. fetch是浏览器内置的API,用于发送网络请求.它基于Promise的方式来进行网络通信.和axios类似.但是功能和封装级别比axios更为简单—项目简单,不想导入axios时适用

Generator

这一节咱们来学习generator

传送门-Generator

Generator对象由生成器函数返回并且它符合可迭代协议和迭代器协议.他可以用来控制流程,语法行为和之前学习的函数不一样

Generator-核心语法

核心语法:

  1. 如何定义生成器函数:
  2. 如何获取generator对象
  3. yield表达式的使用
  4. 通过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-核心语法

  1. 可以通过生成器函数(function* xxx(){})来生成Generator对象:
  2. 通过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)

核心步骤:

  1. 定义生成器函数
  2. 内部使用循环,通过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生成器

  1. 生成器函数内部的代码会在调用next方法时执行,利用这一特点,可以实现任意的生成器,需要时调用next即可获取结果

Generator-流程控制

遇到yield表达式时会暂停后续的操作

**需求:**使用Generator实现流程控制

function* weatherGenerator() {// 逻辑略yield axios()
}
// 获取Generator实例
const weather = weatherGenerator()
// 依次获取 北上广深的天气 (axios)
weather.next()

核心步骤:

  1. yield后面跟上天气查询逻辑
  2. 接口文档-天气预报
  3. 参考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-流程控制

  1. 使用Generator控制流程的本质是利用yield关键字来分隔逻辑比如示例中依次调用了多个接口,通过yield分隔,通过next来触发调用

参考资料

  1. 阮一峰-《ECMAScript 6 教程》
  2. 图灵社区-JavaScript高级程序设计

相关文章:

JS原理-笔记(1/3)

JS原理-笔记&#xff08;1/3&#xff09; 知识点自测 今天课程中涉及到的已学习知识点 函数的call方法-文档链接 // 以指定的this调用函数&#xff0c;并通过 从第二个参数开始依次传递参数 function func(food,drink){console.log(this)console.log(food)console.log(drink)…...

Django创建应用、ORM的进阶使用及模型类数据库迁移

1 Django项目创建第一个应用 Django 项目就是基于 Django 框架开发的 Web 应用&#xff0c;它包含了一组配置和多个应用&#xff0c;我们把应用称之为 App&#xff0c;在前文中对它也做了相应的介绍&#xff0c;比如 auth、admin&#xff0c;它们都属于 APP。 一个 App 就是一…...

tcpdump 如何使用

tcpdump 是一个在Unix和类Unix系统上运行的网络抓包工具&#xff0c;它用于捕获网络流量并将其转储到文件中以供后续分析。tcpdump非常强大&#xff0c;可以用于监控、调试和分析网络通信&#xff0c;用于排查网络问题以及安全审计。以下是关于如何使用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 安全策略限制&#xff0c;在 cross-request 升级到 3.0 后&#xff0c; 不再支持文件上传功能&#xff0c;并且需要通过以下方法查看 network:1.首先在chrome 输入 > chrome://extensions打开扩展页2.开启开发者模式3.点击 cross…...

自动驾驶(apollo)

&#x1f493;博主csdn个人主页&#xff1a;小小unicorn &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 自动驾驶技术 引言自动驾驶的基本原理自动驾驶的技术挑战自动驾驶的潜在影响结…...

web3.0涉及的技术

非同质化代币 非同质化代币&#xff08;Non-Fungible Tokens&#xff0c;NFTs&#xff09;是一种数字资产&#xff0c;与传统的加密货币&#xff08;如比特币或以太币&#xff09;不同&#xff0c;它们具有独特性和不可替代性。NFTs 是基于区块链技术的数字资产&#xff0c;用…...

26. 不相同的字符串(第一期模拟笔试)

题目&#xff1a;样例&#xff1a; 输入 1 abab 输出 2 思路&#xff1a; 这里的题目要求我们要最少操作删除次数&#xff0c;我们可以先统计每个字符个数&#xff0c;然后开始删除&#xff0c;每操作删除一次&#xff0c;就会产生一个新字符&#xff0c;ans r[i] >> 1…...

Rethink LSTMGRU

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

状态管理艺术——借助Spring StateMachine驭服复杂应用逻辑

文章目录 1. 什么是状态2. 有限状态机概述3. Spring StateMachine4. Spring StateMachine 入门小案例4.1 接口测试 5. 总结 1. 什么是状态 在开发中&#xff0c;无时无刻离不开状态的一个概念&#xff0c;任何一条数据都有属于它的状态。 比如一个电商平台&#xff0c;一个订…...

获取和设置小程序和h5的页面栈

获取页面栈&#xff1a; 语法&#xff1a; let pages getCurrentPages(); 设置页面栈&#xff1a; 小程序语法&#xff1a; pages.data H5语法&#xff1a; pages let pages getCurrentPages(); let page pages[pages.length - 2]; if(page.route "pages/conf…...

Mysql基于成本选择索引

本篇文章介绍mysql基于成本选择索引的行为&#xff0c;解释为什么有时候明明可以走索引&#xff0c;但mysql却没有走索引的原因 mysql索引失效的场景大致有几种 不符合最左前缀原则在索引列上使用函数或隐式类型转换使用like查询&#xff0c;如 %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&#xff1a;单张数据表中的数据图表生成 图表统计&#xff0c;查看部门人数统计这里实现的时单张表中的数据实现部门人数折线统计图展示。 <script type"text/javascript">// 利用AjAx来获取后台传入的数据&#xff08;Responsebody注解传入的&…...

GLSL ES着色器 精度限定字

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

webrtc的FULL ICE和Lite ICE

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

flink的几种常见的执行模式

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

蓝桥杯备赛Day8——队列

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

用滑动条做调色板---cv2.getTrackbarPos(),cv2.creatTrackbar()

滑动轨迹栏作调色板 cv.createTrackbar(‘R’, ‘image’, 0, 255, nothing) 参数&#xff1a;哪个滑动轨迹栏&#xff0c;哪个窗口&#xff0c;最小值&#xff0c;最大值&#xff0c;回调函数 cv.getTrackbarPos(‘R’, ‘image’) 参数&#xff1a;轨迹栏名&#xff0c;窗口…...

dubbo 服务注册使用了内网IP,而服务调用需要使用公网IP进行调用

一、问题描述&#xff1a; 使用dubbo时&#xff0c;提供者注册时显示服务地址ip为[内网IP:20880]&#xff0c;导致其他消费者在外部连接的情况下时&#xff0c;调用dubbo服务失败 二、解决办法 方法一、修改hosts文件 &#xff08;1&#xff09;. 先查询一下服务器的hostna…...

外传-Midjourney的局部重绘功能

今天在抄袭。。。啊不&#xff0c;借鉴 midjourney 官网教程的时候&#xff0c;发现多了一个 局部重绘的功能&#xff0c;意外发觉还不错&#xff0c;分享一下用法。 先给大家说一下&#xff0c;我这段时间都在学习 SD&#xff0c;局部重绘是基操&#xff0c;而 MJ 一直是次次…...

Spring Boot 中使用 Poi-tl 渲染数据并生成 Word 文档

本文 Demo 已收录到 demo-for-all-in-java 项目中&#xff0c;欢迎大家 star 支持&#xff01;后续将持续更新&#xff01; 前言 产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档&#xff0c;你来安排下」 项目中有这么一个需求&#xff0c;需要将用户…...

Java基础(二十一)十点半游戏

十点半游戏 十点半是一种流行的纸牌游戏&#xff0c;可以说是一种变体的二十一点游戏。游戏的规则是&#xff0c;每个玩家根据所拿到的牌点数的总和来决定是否继续要牌。目标是尽量接近但不超过十点半的点数&#xff0c;超过十点半即为爆牌。如果两名玩家都未爆牌&#xff0c;…...

第8节-PhotoShop基础课程-常用快捷键汇总

文章目录 前言1.工具栏1.移动工具 V2.矩形框选工具 M3.套索工具 L4.魔棒工具 W5.裁剪工具 C6.吸管工具 I7.污点修复工具 J8.仿制图章工具 S9.历史记录画笔工具 Y10.橡皮檫工具 E11.油漆桶工具 G12 减淡工具 O13.钢笔工具 P14 横排文字工具 T15.路径选择工具 A16 椭圆工具 U17 抓…...

Redis带你深入学习数据类型set

目录 1、set 2、set相关命令 2.1、添加元素 sadd 2.2、获取元素 smembers 2.3、判断元素是否存在 sismember 2.4、获取set中元素数量 scard 2.5、删除元素spop、srem 2.6、移动元素smove 2.7、集合中相关命令&#xff1a;sinter、sinterstore、sunion、sunionstore、s…...

Json“牵手”易贝商品详情数据方法,易贝商品详情API接口,易贝API申请指南

易贝是一个可让全球民众在网上买卖物品的线上拍卖及购物网站&#xff0c;易贝&#xff08;EBAY&#xff09;于1995年9月4日由Pierre Omidyar以Auctionweb的名称创立于加利福尼亚州圣荷塞。人们可以在易贝上通过网络出售商品。2014年2月20日&#xff0c;易贝宣布收购3D虚拟试衣公…...

《AI一键生成抖音商品种草文案》让你秒变带货王!

在这个数字化的时代&#xff0c;我们的生活被各种应用所包围&#xff0c;其中&#xff0c;抖音作为一款短视频分享平台&#xff0c;已经成为了我们生活中不可或缺的一部分。然而&#xff0c;作为一名抖音创作者&#xff0c;你是否曾经遇到过这样的困扰&#xff1a;在创作商品种…...

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池

博客系统&#xff08;二&#xff09; 博客系统获取当前用户的信息对密码进行加密和解密的操作设置统一的数据返回格式设置未登录拦截设置线程池 博客系统 博客系统是干什么的&#xff1f; CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统&#xff0c;这是…...

Postman接口测试工具

Postman接口测试工具 Postman简介Postman 发送一个请求postman创建一个集合Postman 快捷键Postman设置postman请求postman历史postman请求排错postman集合简介postman创建和共享集合postman管理集合postman数据导入导出postman测试脚本postman环境变量和全局变量...

为wordpress首页添加关键词/百度查重工具

一、ELK 相关资料 ELK官网&#xff1a; 点击打开链接 ELKstack 中文指南&#xff1a;点击打开链接 二、安装过程 节点1&#xff1a;172.214.5.19 节点2&#xff1a;172.216.18.40 节点3&#xff1a;172.216.33.100 1、Java安装 # yum -y install java-1.8.0 # v…...

上海免费网站建设/宁波seo教学

作者&#xff1a;张志朋出处&#xff1a;https://blog.52itstyle.com题记工作也有几多年了&#xff0c;无论是身边遇到的还是耳间闻到的&#xff0c;多多少少也积攒了自己的一些经验和思考&#xff0c;当然&#xff0c;博主并没有太多接触高大上的分布式架构实践&#xff0c;相…...

网站seo搜索引擎优化教程/百度招聘2022年最新招聘

【题目】A. A String Game 【题意】给定目标串S和n个子串Ti&#xff0c;Alice和Bob轮流选择一个子串操作&#xff0c;必须且只能在子串末尾添加一个字符使得新串也是S的子串&#xff0c;不能操作即输&#xff0c;求胜利者。|S|<10^5,n<100。多组数据&#xff0c;保证Σ|S…...

坪地网站建设/推广方案模板

战神引擎架设正常游戏怎么不开门&#xff1f;战神引擎正常搭建游戏成功后怎么会打不开门&#xff1f;这个怎么解决&#xff0c;跟着idc02大肥羊往下看战神引擎的问世&#xff0c;让传奇手游正式进入平民化&#xff0c;在本站就有一大把的手游服务端&#xff0c;但目前手游和端游…...

大网站前端怎么做的/福州网站建设团队

井下运输是矿山生产的一个关键环节&#xff0c;随着国家对矿井安全的日益重视和监管力度的不断加强&#xff0c;大中型采矿企业井下运输安全生产监控系统开始研制和装备。中文名矿下交通信号控制系统外文名Mine Ramp Traffic Monitor & Auto Control System性 质控制系统…...

seo短期培训班/英语seo

美国《福布斯》双周刊网站5月24日刊载题为《到2023年区块链解决方案支出可能超过160亿美元》的文章&#xff0c;作者系卢克菲茨帕特里克&#xff0c;文章认为区块链将给四大行业带来巨变。 这是1月8日在美国拉斯维加斯消费电子展上拍摄的欧姆龙公司的HeartGuide可穿戴设备。美…...