1.call、apply的区别:
call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。
fn.call(obj, arg1, arg2, arg3…);
fn.apply(obj, [arg1, arg2, arg3…]);
2.call、apply与bind的差别:
call和apply改变了函数的this上下文后便执行该函数,而bind则是返回改变了上下文后的一个函数。
例子:
let person1={
name:"张三",
age:12,
say(...args){
console.log(`姓名:${this.name},年龄:${this.age},参数:${args}`)
}
}
let person2={
name:"李四",
age:14
}
//call第一个参数: 借用方法的对象,可以传递多个参数
person1.say.call(person2,123,2,5,3);
//姓名:李四,年龄:14,参数:123,2,5,3
//call第一个参数: 借用方法的对象,允许传递第二个参数必须是数组
person1.say.apply(person2,[2,3,4,5]);
//姓名:李四,年龄:14,参数:2,3,4,5
// bind只是改变了this的指向,但是并没有调用say方法,加一个()执行
person1.say.bind(person2,[1,2])();
// 姓名:李四,年龄:14,参数:1,2
person1.say.bind(person2,2,3,4)();
// 姓名:李四,年龄:14,参数:2,3,4
1
2
3
手动封装call,apply,bind
//手动封装call
Function.prototype.myCall=function (obj,...args) {
obj =obj || window; //没有指定this,也就是说没有传object这个参数,this指向window
const key = Symbol() //方法,比如say需要是一个唯一的值
obj[key]=this 给obj添加一个方法,指向this
obj[key](...args)//调用这个方法并把参数传过去
delete obj[key] //使用完后销毁方法
}
person1.say.myCall(person2,123,2,5,3);
//手动封装apply
//情况:1.一个参数,2.传递两个 (1)数组(2)非数组
Function.prototype.myApply=function (obj,...args) {
let obj1 = arguments[0] || window;
const args1 = arguments[1];
const key = Symbol() //方法,比如say需要是一个唯一的值
obj1[key]=this 给obj1添加一个方法,指向this
let result;
if(args){//args存在
if(Array.isArray(args)){//如果第二个参数是数组
result =obj1[key](...args);
}else if(arguments.length===2){//第二个参数是一个数
result =obj1[key](args);
}else {
console.error("myApply传递多个参数的时候,第二个参数必须是数组");
}
}else {
result =obj1[key]();//没有参数,直接调用
}
}
person1.say.myApply(person2,[123,11,5,3]);
//姓名:李四,年龄:14,参数:123,11,5,3
//手动封装bind
Function.prototype.myBind=function (obj,...args) {
let self = this;
return function () {
let newArgs =args.concat(...arguments);//arguments是当前function的参数,也就是下面的256
self.myCall(obj,newArgs);
}
}
person1.say.myBind(person2,123,2,5,3)(256);