1.相同点与不同点
相同点:都是改变函数this指向 不同点:
1.apply传参方式与其余不同,apply是以数组形式传参,fn.apply(this,[...arguments])
2.返回值不同,apply和call会直接执行这个函数,并且返回这个函数执行后的返回值,bind则会返回原函数的拷贝,并且指定好了this,还有初始参数
2.手动实现call,apply,bind
1.call
Function.prototype.myCall = function (youThis, ...arg){
youThis = youThis || window || global //如果this是undefind或者null,则将this指向全局对象
const prop = Symbol() //设置唯一值
youThis[prop] = this //这里的this就是调用myCAll的函数,谁调用,函数就指向谁
let result = youThis[prop](...arg)//用result将函数运行结果存储并返回
delete youThis[prop]//删除函数参数
return result
}
const obj = {
a: 1,
}
function log() {
console.log(this);
}
log()// global or window
log.myCall(obj)// 1
为什么用Symbol做唯一值
Function.prototype.myCall = function (youThis, ...arg){
youThis = youThis || window || global
youThis.fn = this
let result = youThis.fn(...arg)
return result
}
const obj = {
a: 1,
}
function dd1() {
console.log(this);
}
function dd2() {
console.log(this);
}
function dd3() {
console.log(this);
}
dd1.myCall(obj)
dd2.myCall(obj)
dd3.myCall(obj)
如果想这样的代码,youThis.fn 一直会被dd3这个函数覆盖,无法拿到dd2,dd1
2.apply
apply方法和call只是传参方式不同,知道call方法怎么写,apply就差不多,就扩展运算符传把数组给函数就行了
Function.prototype.myApply = function (youThis, argArray){
youThis = youThis || window || global
const prop = Symbol()
youThis[prop] = this
let result = youThis[prop](...argArray)
delete youThis[prop]
return result
}
const obj = {
ff: 1,
gg:[1,2,3,4]
}
function dd(a,b,c,d) {
console.log(this.gg[a]);
console.log(this.gg[b]);
console.log(this.gg[c]);
console.log(this.gg[d]);
}
dd.myApply(obj,[0,1,2,3])
3.bind
利用闭包保存this,返回一个函数,其实方法都差不多
Function.prototype.myBind = function (yourThis, ...arg) {
let self = this //利用闭包保存this,因为bind赋给变量是函数体,不使用闭包的话无法在全局中找到保存的this
return function (...other) { //返回函数,这里的this保证函数可以继续传参
return self.apply( yourThis,[...arg,...other])//返回指定函数this和参数的返回值
}
}
const obj = {
ff: 1,
gg:[1,2,3,4]
}
function dd(a,b,c,d) {
console.log(this.gg[a]);
console.log(this.gg[b]);
console.log(this.gg[c]);
console.log(this.gg[d]);
}
const newFn = dd.myBind(obj, 0,1,2,3)
newFn()
如果定义的函数怎么使用呢
Function.prototype.myBind = function (yourThis, ...arg) {
let self = this this
return function (...other) {
console.log(this)//这里this是什么
return self.apply( yourThis,[...arg,...other])
}
}
const obj = dd.myBind(obj, 0,1,2,3)
const aa = new newFn()
这里this会打印出这个obj ,因为new操作符会把函数体里面的this指向实例,所以这个myBind还有点问题 不符合MDN描述
以下为完善的版本
Function.prototype.myBind = function (yourThis, ...arg) {
let self = this this
const bound = function (...other) {
const args = [...arg,...other]
const isNew = this instanceof bound
if(isNew){
return new self(...args)
}else{
return self.apply( yourThis,args)
}
}
return bound
}