Function.prototype具有三个方法:call/apply/bind 每一个函数都是Function内置的实例,所以都可以使用这个三个方法
作用:三个方法都是强制改变函数中的this指向,语法上有点差异,对箭头函数无效
call和apply调用语法:
函数.call(context,params1,params2,…)
函数.apply(context,[params1,params2,…])
Function.prototype.call()
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
函数.call调用作用是基于__proto__找到Function.prototype.call方法
然后把找到的call方法执行过程中,把this执行改为context了,也帮我们把函数执行了,也把参数传递给调用的函数了
备注:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
Function.prototype.apply()
apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或一个类数组对象)的形式提供的参数。
备注: 虽然这个函数的语法与 call() 几乎相同,但根本区别在于,call() 接受一个参数列表,而 apply() 接受一个参数的单数组。
Function.prototype.bind()
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用
call方法实现
call实现—使用eval函数实现
Function.prototype.call= function (ob) {
// 如果不指定为this指向 默认window
ob = ob || window;
//把调用函数在oj里面新添加属性fn存一份
ob.fn = this;
//处理多个参数问题 排除第一个ob参数 从下标1开始获取剩余参数
const args = [];
for (let i = 1; i < arguments.length; i++) {
//必须拼接 不然eval解析{}或者字符串就会出现错误
args.push(`arguments[${i}]`);
}
//oj对象调用fn函数 this指向改为ob
//源码中使用eval函数处理多个参数 es6未出现之前的处理方式
//存在问题
const result = eval(`ob.fn(${args})`);
// 执行完删除fn属性 防止原来obj结构被修改
delete ob.fn;
// 接收函数返回值
return result;
};
Es6实现call方法
Function.prototype.call= function (ob, ...args) {
// 如果不指定为this指向 默认window
ob = ob || window;
//把调用函数在oj里面新添加属性fn存一份
ob.fn = this;
//oj对象调用fn函数 this指向改为ob
const result = ob.fn(...args);
// 执行完删除fn属性 防止原来obj结构被修改
delete ob.fn;
// 接收函数返回值
return result;
};
apply实现
Function.prototype.apply= function (ob, args) {
// 如果不指定为this指向 默认window
ob = ob || window;
//把调用函数在oj里面新添加属性fn存一份
ob.fn = this;
//oj对象调用fn函数 this指向改为ob
let result = args ? ob.fn(...args) : ob.fn();
// 执行完删除fn属性 防止原来obj结构被修改
delete ob.fn;
// 接收函数返回值
return result;
};
bind实现
Function.prototype.bind= function (context, ...params) {
// context->obj params->[10,20] this->fn
let self = this;
return function proxy(ev) {
// this->submit ev->事件对象
params = params.concat(ev);
return self.call(context, ...params);
};
};