JS原理 知识点自测 call🍧 apply🍧 bind🍧 剩余参数🍧 Promise🍧 URLSearchParams🍧 Object.create🍧 Object.assign🍧
函数的call
方法-文档链接
1 2 3 4 5 6 7 8 9 10 11 12 function func (name,drink ){ console .log (this ) console .log (name) console .log (drink) } const obj = { name :'kilito' } func.call (obj,'kilito' ,'咖啡' )
函数的apply
方法-文档链接
1 2 3 4 5 6 7 8 9 10 11 12 function func (name,drink ){ console .log (this ) console .log (name) console .log (drink) } const obj = { name :'kilito' } func.apply (obj,['xiaoqing' ,'咖啡' ])
函数的bind
方法-文档链接
1 2 3 4 5 6 7 8 9 10 11 12 13 function func (food, drink ) { console .log (this ) console .log (food) console .log (drink) } const obj = { name : 'kilito' } 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 : 'kilito' , 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 : 'kilito' , 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 )
this🍧 继承🍧 class🍧 fetch🍧 geneator🍧
JS中的this
传送门:MDN-this
传送门:MDN-call
传送门:MDN-apply
传送门:MDN-bind
传送门:MDN-箭头函数
传送门:MDN-剩余参数
传送门:MDN-Symbol
如何确认this指向: 在绝大多数情况下,函数的调用方式决定了 this
的值(运行时绑定)
谁调用就是谁,直接调用就是window
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 function func ( ) { console .log (this ) } func ()const person = { name : 'jack' , sayHi : function ( ) { console .log (this ) function inner ( ) { console .log (this ) } inner () }, sayHello ( ){ console .log (this ) setTimeout (function ( ){ console .log (this ) }) } } person.sayHi () person.sayHello ()
如何改变this指向 主要有2类改变函数内部this
指向的方法:
调用函数并传入具体的this
:
call
:
参数1:this
() (希望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 : 'kilito' } 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 function funcB (p1, p2 ) { console .log ('funcB-调用' ) console .log (this ) console .log ('p1:' , p1) console .log ('p2:' , p2) } const person = { name : 'kilito' } const bindFuncB = funcB.bind (person, 123 )bindFuncB (666 )const student = { name : 'kilito' , sayHi : function ( ) { console .log (this ) const inner = ( ) => { console .log ('inner-调用了' ) console .log (this ) } inner () } } student.sayHi () const person = { name : 'kilito' , sayHi ( ) { console .log (this ) setTimeout (()=> { console .log (this ) },1000 ) }, sayHello :()=> { console .log (this ) } } person.sayHello ()
手写call方法 这一节咱们来实现myCall
方法,实际用法和call
方法一致,核心步骤有4步
1 2 3 4 5 6 7 8 9 10 11 const obj2 = { name : 'kilito' } function func2 (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } func2.myCall (obj2, '咖啡' , '西兰花炒蛋' )
如何定义myCall
?
如何让函数内部的this
为某个对象?
如何让myCall
接收参数2-参数n?
使用Symbol 调优myCall
?
添加到原型上,所有函数均可调用
通过给对象动态添加属性的方式来指定 this
…args 剩余参数 实现参数传递
通过 Symbo 解决了和默认属性重名的问题
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 57 Function .prototype .myCall = function ( ) { } Function .prototype .myCall = function (thisArg ) { thisArg.func = this const res = thisArg.func () delete thisArg.func return res } Function .prototype .myCall = function (thisArg, ...args ) { thisArg.func = this const res = thisArg.func (...args) delete thisArg.func 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 obj2 = { name : '我是小小黑' } function func2 (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } func2.myCall (obj2, '咖啡' , '西兰花炒蛋' )
1 2 3 4 5 6 const s1 = Symbol ()const s2 = Symbol ()const s3 = Symbol ('kilito' )console .log (s1 === s2)
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 const obj2 = { name : '我是小小黑' } function func2 (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } func2.myApply (obj2, ['咖啡' , '西兰花炒蛋' ])
如何定义myApply
? 函数Function的原型上
如何让函数内部的this
为某个对象?给对象动态增加方法,方法为原函数,通过对象调用即可
如何让myApply
接收数组形式的参数列表? 定义一个参数接收数组即可 形参: args,调用时,…args
使用Symbol 调优myApply
?和原对象的属性重名
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 Function .prototype .myApply = function ( ) { } Function .prototype .myApply = function (thisArg ) { thisArg['fn' ] = this const res = thisArg['fn' ]() delete thisArg['fn' ] return res } Function .prototype .myApply = function (thisArg, args ) { 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 obj2 = { name : '我是小小黑' } function func2 (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } func2.myApply (obj2, ['咖啡' , '西兰花炒蛋' ])
小结:手写apply方法
如何定义myApply
? 函数的原型上
如何让函数内部的this
为某个对象? 动态给对象添加方法,通过对象的方式调用方法
如何让myApply
接收数组形式的参数列表? 形参: args,调用时,…args
使用Symbol 调优myApply
?避免和默认属性重名
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 const obj = { name : '我是小小黑' } function func (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } const bindFunc = func.bind (obj, '可乐' )bindFunc ('西蓝花炒蛋' )
如何返回一个绑定了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 Function .prototype .myBind = function (thisArg ) { return () => { this .call (thisArg) } } Function .prototype .myBind = function (thisArg, ...args ) { return (...args2 ) => { this .call (thisArg, ...args, ...args2) } } const obj = { name : '我是小小黑' } function func (drink, food ) { console .log (`我叫${this .name} ,我喜欢喝${drink} ,我爱吃${food} ` ) } const bindFunc = func.bind (obj, '可乐' )bindFunc ('西蓝花炒蛋' )
小结:手写bind方法
如何返回一个绑定了this
的函数?
如何实现绑定的参数,及传入的参数合并?
1 2 3 4 5 Function .prototype .myBind = function (thisArg, ...args ) { return (...args2 ) => { 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 24 25 26 27 28 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 () console .log (s1 === s2) console .log (s1.foods === s2.foods ) s2.foods .push ('西葫芦' ) s2.sayFoods () s1.sayFoods ()
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-组合继承 通过组合继承,结合原型链继承和构造函数继承2种方法的优点
核心步骤:
通过原型链继承公共的属性和方法
通过构造函数继承实例独有的属性和方法
特点: 调用了2次构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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-原型式继承 直接基于对象实现继承
**核心步骤:**对某个对象进行浅拷贝(工厂函数或Object.create ),实现继承
**缺点:**父类中的引用数据类型,会被所有子类共享
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 const parent = { name : 'parent' , age : 25 , friend : ['rose' , 'ice' , 'robot' ], sayHi ( ) { console .log (this .name , this .age ) } } function objectFactory (obj ) { function Fun ( ) { } Fun .prototype = obj return new Fun () } const son1 = objectFactory (parent)const son2 = objectFactory (parent)son1.friend .push ('lucy' ) console .log (son1.friend ) console .log (son2.friend )
ES5-寄生式继承 核心步骤:
定义工厂函数,并在内部:
对传入的对象进行浅拷贝(公共属性/方法)
为浅拷贝对象增加属性/方法(独有属性/方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const parent = { name : 'parent' , foods : ['西蓝花' , '炒蛋' , '花菜' ] } function createAnother (origin ) { const clone = Object .create (origin) clone.sayHi = function ( ) { console .log ('你好' ) } return clone } const son1 = createAnother (parent)const son2 = createAnother (parent)
1 2 3 4 5 6 7 8 9 10 11 const father = { name : 'kilito' , age : 25 , foods : ['西瓜' , '西兰花' ,'西葫芦' ] } const newF = Object .create (father)console .log (newF === father) console .log (newF.foods === father.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 24 25 26 27 28 29 30 31 32 33 34 35 36 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 )
JS继承-ES6
传送门:mdn类
传送门:阮一峰ES6-class
传送门:mdn-super
ES6中推出了class
类,是用来创建对象的模板.class
可以看作是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
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 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实现继承 关键语法:
子类 通过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私有,静态属性和方法 补充语法:
私有 属性/方法的定义及使用(内部调用)
静态 属性/方法的定义及使用(类直接访问)
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 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 )
fetch
这一节咱们来学习内置函数fetch
传送门-fetch
传送门-Response
传送门-Headers
全局的fetch
函数用来发起获取资源请求.他返回一个promise
,这个promise
会在请求响应后被resolve
,并传回Response对象
fetch
核心语法
fetch
结合URLSearchParams
发送get请求:
const obj = {
name:'jack',
age:18
}
name=jack&age=17
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 3. `fetch`发送post请求,提交`JSON`数据 4. `fetch`发送post请求,提交`FormData`数据 ### 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 document.querySelector('.request').addEventListener('click',() => { // 1. fetch(url地址) ===> Promise对象 fetch('http://hmajax.itheima.net/api/news').then(response => { // console.log(response) // 2. 请求成功之后, resolve --> then 获取 response // 3. 调用 json 方法,获取解析之后的结果,返回Promise response.json().then(res => { console.log(res) }) }) }) // async await 改写 document.querySelector('.request').addEventListener('click', async() => { const response = await fetch('http://hmajax.itheima.net/api/news') const res = response.json() console.log(res) })
fetch结合URLSearchParams发送get请求: 需求:
使用fetch
结合URLSearchParams
调用地区查询接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ;(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 () })()
post请求-提交JSON 需求:
fetch
发送post请求,提交JSON
数据
测试接口-用户注册
核心步骤:
根据文档设置请求头
通过配置项设置,请求方法,请求头,请求体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; (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
函数的第二个参数可以设置请求头,请求方法,请求体
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 >
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 32 33 34 35 36 37 38 39 40 41 42 43 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-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-流程控制 遇到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 26 27 28 29 30 31 32 33 <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 >