一、call apply bind的使用
apply、bind 和 call 都用于改变函数中的 this 指向。call 通过 func.call(thisArg, arg1, arg2, ...) 的形式调用,参数逐个传递;apply 通过 func.apply(thisArg, [arg1, arg2, ...]) 的形式调用,参数以数组形式传递;bind 使用 func.bind(thisArg, arg1, arg2, ...) 返回一个新的函数,不立即执行,可以稍后调用并传递参数。
注意事项如下:
- 无法给箭头函数绑定this
- apply、call 和 bind 都可以手动设置函数内部的 this 指向,但如果传递 null 或 undefined,this 将默认指向全局对象(非严格模式下是 window,严格模式下是 undefined)
- bind 返回函数:bind 并不会立即执行函数,而是返回一个新的函数,可以稍后调用;这使其特别适合在事件处理程序等场景中使用。
- 不可改变的 this:对于使用 bind 绑定了 this 的函数,其 this 指向是不可改变的,后续调用 call 或 apply 也无法重新改变它的 this。
// call apply and bind 给函数绑定this指向的方法
// 其中call apply会立即执行并返回结果, apply传入的是数组参数
// bind会返回一个新的函数,可以在bind的时候传递部分参数,等调用再传递部分参数
// call
const person = {
name: "Tom",
}
function func(num1, num2){
console.log(this);
return num1 + num2
}
console.log(func.call(person, 1 ,3 )); // Tom 4
// apply
console.log(func.apply(person,[1, 3])) // Tom 4
// bind
const newfunc = func.bind(person, 1, 2)
console.log(newfunc()); // Tom 3
const newfunc2 = func.bind(person)
console.log(newfunc2(1, 2)) // Tom 3
二、call apply bind 的手写代码实现
在手动实现 call、apply 和 bind 时,关键步骤包括使用 Symbol 生成一个唯一的函数键,将目标函数临时赋值给 thisarg 对象的该键,从而改变 this 的指向。对于 myCall,函数通过展开参数直接调用,并传入单独的参数列表;myApply 则接收一个参数数组并通过展开运算符传递给函数。myBind 返回一个新函数,这个新函数在调用时会结合预设的参数和后续传入的参数,通过 call 方法执行原函数。最后,临时添加的函数属性在调用后被删除,以避免影响原对象。
// 手动实现call apply bind
Function.prototype.myCall = function(thisarg, ...args){
const fn = Symbol("fn");
thisarg[fn] = this;
const res = thisarg[fn](...args)
delete thisarg[fn]
return res
}
Function.prototype.myAplly = function(thisarg, args){
const fn = Symbol("fn")
thisarg[fn] = this
const res = thisarg[fn](...args)
delete thisarg[fn]
return res
}
Function.prototype.myBind = function(thisarg, ...args){
return (...args2) => {
return this.call(thisarg, ...args, ...args2)
}
}
func.myCall(person, 1, 2) // Tom 3
func.myAplly(person, [1, 2]) // Tom 3
const newfunc3 = func.myBind(person, 1, 2)
console.log(newfunc3()) // Tom 3
三、es6前的类实现与继承 class语法糖的使用
下述代码展示了ES6中的class语法如何作为ES5函数构造器的语法糖,简化了类的创建和继承。在ES5中,类通过函数构造器定义成员变量,并使用原型链添加成员方法,继承则通过call调用父类构造函数并使用Object.create设置原型。ES6引入了class关键字,使类的定义更直观,包括构造函数、实例方法和继承(使用extends和super)。此外,ES6还支持静态方法(通过static定义,仅可通过类本身调用)和私有变量/方法(使用#前缀,外部无法访问),进一步增强了封装性和代码组织的清晰性。
// class的使用 class是es6中新增的语法糖,本质上还是函数
// 在es6之前我们使用函数构造器来创建类
// es6之前 成员变量
function Person(name){
this.name = name;
}
// es6之前 成员方法
Person.prototype.sayName = function(){
console.log(this.name);
}
const tom = new Person("Tom")
// es6之前实现继承
function Student(name, grade){
// 调用父类构造函数,并且指定this指向未new出来的示例对象
// 实现将父类的属性绑定到子类的实例对象上
Person.call(this, name)
this.grade = grade
}
// 继承父类的方法
Student.prototype = Object.create(Person.prototype,{
constuctor: Student
})
const student = new Student("Jerry", 1)
student.sayName() // Jerry
// es6之后
class newPerson{
name
eps = 0.01
constructor(name){
this.name = name;
}
sayName(){
console.log(this.name)
}
}
const jerry = new newPerson("Jerry")
jerry.sayName() // Jerry
class newStudent extends newPerson{
constructor(name, grade){
super(name)
// 动态创建属性
this.grade = grade
}
getGrade(){
console.log(this.grade)
}
}
const newstudent = new newStudent("Jerry", 1)
newstudent.sayName() // Jerry
newstudent.getGrade() // 1
// 静态方法与隐私变量
// 静态方法是类的方法,不是实例对象的方法,可以直接通过类调用
// 隐私变量是在类内部定义的变量,外部无法访问(调试时可以访问)
class newPerson2{
// 隐私变量
#name
// 静态变量
static secret = "secret"
constructor(name){
this.#name = name;
}
sayName(){
console.log(this.#name)
}
// 静态方法
static sayHello(){
console.log("Hello")
}
// 隐私方法
#sayHello(){
console.log("Hello #Hello")
}
getinfo(){
this.#sayHello()
}
}
const tom2 = new newPerson2("Tom")
tom2.sayName() // Tom
newPerson2.sayHello() // Hello
tom2.getinfo() // Hello #Hello
四、fetch的基础使用
// 下面将介绍fetch的使用, 常用的还有axios ajax,当然一般项目实践中使用axios
// fetch是es6新增的api,用于替代ajax,fetch是基于promise实现的,相当于axios的简化版本
// 下面将分别演示传递searchparams, json, formdata三种常见的场景
// 1. searchparams
const gerinfo = async () => {
const params = new URLSearchParams()
params.append("name", "Tom")
params.append("age", 18)
const res = await fetch("https://api.github.com/users/zhengyuanbo?" + params.toString())
if(res.status >= 200 && res.status < 300){
const data = await res.json()
console.log(data)
}else{
console.log("error")
}
}
// 2. json
const postinfo = async () => {
const res = await fetch("https://api.github.com/users/zhengyuanbo", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Tom",
age: 18
})
})
if(res.status >= 200 && res.status < 300){
const data = await res.json()
console.log(data)
}else{
console.log("error")
}
}
// 3. formdata
const postinfo2 = async () => {
const formData = new FormData()
formData.append("name", "Tom")
formData.append("age", 18)
const res = await fetch("https://api.github.com/users/zhengyuanbo", {
method: "POST",
body: formData
})
if(res.status >= 200 && res.status < 300){
const data = await res.json()
console.log(data)
}else{
console.log("error")
}
}
五、generator的使用
在同步场景中,生成器通过 yield 关键字暂停函数执行,并通过 next() 方法逐步恢复执行,每次调用 next() 返回包含 value 和 done 属性的对象,便于控制执行流程。在异步场景中,生成器可以通过 yield 暂停等待 Promise 的解决,然后使用链式的 then 方法处理异步结果,实现异步操作的顺序执行。然而,使用生成器处理异步任务较为繁琐,因此在 ES7 中引入了 async 和 await 语法糖,简化了异步代码的编写。
// 在处理异步问题当中,除了使用回调函数以及promise,还可以使用generator
// 首先看一下generator在同步场景中的使用
function* gen(){
console.log("start")
yield "1"
console.log("middle")
yield "2"
console.log("end")
}
const g = gen()
let res = g.next() // start
console.log(res) // { value: '1', done: false }
res = g.next() // middle
console.log(res) // { value: '2', done: false }
res = g.next() // end
console.log(res) // { value: undefined, done: true }
// 通过上面的观察得出在generator中使用yield可以暂停函数的执行,通过next方法可以继续执行函数
// 执行next方法将会含有两个属性的对象,value是yield后面的返回值,done表示是否执行完毕,true为执行完毕,且此时value为undefined
// generator在异步场景中的使用
function* gen2(){
yield fetch("https://api.github.com/users/zhengyuanbo")
yield fetch("https://api.github.com/users/zhengyuanbo")
}
const g2 = gen2()
g2.next().value
.then(res => res.json())
.then(data => {
console.log(data)
return g2.next().value
})
.then(res => res.json())
.then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
// 从上面可以看到generator可以用于处理异步问题,但是generator的使用比较繁琐,所以es7中引入了async await语法糖
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » call apply bind基础使用与手动实现 class继承与基础使用 fetch的基础使用 generator的使用
发表评论 取消回复