call和apply都可以改变this的指向
请看下面函数的执行
var name = "hello"
var foo = {
name: "wucr"
};
function getName(){
console.log(this.name)
}
getName() //返回值hello
getName.call(foo) // 返回值 wucr
那么如何模拟实现一个call函数呢,请看下面分析
var foo = {
name: "wucr",
getName:function(){
console.log(this.name)
}
}
foo.getName() // wucr
//分析以上的代码,我们可以给对象自己添加一个方法,然后去调用,但是这样就会有一个问题就是都要在对象里面去新增方法,但是我们用 delete 再删除它不就好了~,所以我们的模拟步骤可以是下面三步
1,将函数设为对象的属性
2,执行该函数
3,删除该函数
call函数第一版抹模拟实现
Function.prototype.call1 = function(context){
context.fn = this; // 这里的this指代调用的函数
context.fn();
delete context.fn
}
var name = "hello"
var foo = {
name: "wucr"
};
function getName(){
console.log(this.name)
}
getName.call1(foo) // 返回值 wucr
我们都知道,call里面可以传递很多参数,call(context,arguments1,arguments2…),所以以上的实现不能满足,参数不固定,但是我们可以使用arguments类数组来获取参数
call函数第二版模拟实现
Function.prototype.call2 = function(context){
var args = [];
for(var i =1; i < arguments.length; i++){
args.push(arguments[i])
}
context.fn = this; // 这里的this指代调用的函数
context.fn(...args);
delete context.fn
}
上面第二版没有返回值和当我们不传递context时的判断
call函数终极版模拟实现
Function.prototype.call2 = function(context){
var context = context || window
var args = [];
for(var i =1; i < arguments.length; i++){
args.push(arguments[i])
}
context.fn = this; // 这里的this指代调用的函数
var result = context.fn(...args);
delete context.fn;
return result;
}
结合call的模拟实现apply的实现就很简单了
apply函数终极版模拟实现
Function.prototype.apply = function(context,arr){
var context = context || window;
context.fn = this;
if(!arr){
var result = context.fn()
}else{
var args = [];
for(var i =0; i < arr.length; i++){
args.push(arr[i])
}
var result = eval('context.fn(' + args + ')') // 这里也可以 var result = context.fn(...args);但是这语法是es6
}
return result;
}