call, apply, 和 bind 是 JavaScript 中用于控制函数执行时 this 值的方法。
这其中,call 和 apply 非常相似,它们的第一个参数都是要绑定的 this 值,接下来的参数则是传入函数的参数。它们的区别在于传入的参数的形式不同。
对于 call 方法,之后的参数是要传递给函数的参数列表。
下面是call的例子:
function greet(name,age) {
console.log(`Hello, ${name}!Your number is ${age}`);
}
greet.call(null,' Alice',13); // Hello, join!Your number is 13
而对于 apply 方法,之后的参数需要以数组的形式传递。
相同的例子,使用apply的话就是:
function greet(name,age) {
console.log(`Hello, ${name}!Your number is ${age}`);
}
greet.apply(null,[' Alice',13]); // Hello, join!Your number is 13
无论是 call 还是 apply,它们的作用都是调用函数,并将指定的 this 值和参数传递给函数。它们之间的主要区别在于参数的传递方式。
现在说bind,bind和call的传参方式是一样的,区别是bind不会像call一样当即调用,而是返回一个全新的函数,待你想调用的时候再调用。
下面是例子:
function greet(name,age) {
console.log(`Hello, ${name}!Your number is ${age}`);
}
const hello = greet.bind(null,' Alice',13); // 这里是不会调用的
hello()//Hello, Alice!Your number is 13
接下来便是大伙喜闻乐见的手写call,apply和bind
首先是手写call:
function类的原型链上添加自己写的call给别的函数调用
Function.prototype.myCall = function(target,...args){
target = target || window //当target不存在时,给个window
const symbolKey = Symbol();//创造独一无二的变量
target[symbolKey] = this;//这里的this其实就是函数,将函数加到调用的对象身上去
//例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上
const res = target[symbolKey](...args)//调用函数
delete target[symbolKey];//调用完了立马删掉
return res;//返回结果
}
难点就是这里this赋值的理解,实际上就是把函数(this)当成个对象,然后赋值给target
例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上
apply也是一样的:
Function.prototype.myApply = function(target,...args){
target = target || window //当target不存在时,给个window
const symbolKey = Symbol();//创造独一无二的变量
target[symbolKey] = this;//这里的this其实就是函数,将函数加到调用的对象身上去
//例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上
const res = target[symbolKey](...args)//调用函数
delete target[symbolKey];//调用完了立马删掉
return res;//返回结果
}
完全套用
接下来是bind:
这里困难一点,因为涉及到了闭包
Function.prototype.myBind = function(target,...outArgs){
target = target || {} //如果没有传入target的话,那调用的可不就是个空对象嘛
const symbolKey = Symbol();
target[symbolKey] = this;//再说一次,将调用的函数添加到target身上
return function(...innerArgs){
const res = target[symbolKey](...outArgs,...innerArgs);
//这里传入的参数说下,第一次用bind的时候可以传一次参数,返回的函数调用时也可以再传一次参数
//不需要delect这个函数,必须保证第二次调用时不出问题
return res
}
}
总结到这里就结束了,有什么不明白的可以找我一起探讨