深度解析 call 和 apply 原理
2019-07-18 本文已影响0人
y先生_f18f
call()主要有以下两点特点
- 可以改变我们当前函数点this指向
- 还会让当前函数执行
我们主要根据这两点进行他的原理探讨
//call的实现原理
Function.prototype.call = function(context){
//1、调用call方法的时候会传入this指向,但是在传入的时候可能string字符串,所以我们这里需要Object(context)处理
//2、如果调用的时候没有传入this指向,我们需要指向window
context = context ? Object(context) : window;
//将函数设置为对象的属性
context.fn = this;
//接收传递的参数
let args = [];
//这里i从1开始是因为arguments的第一项是接收我们传递的this指向
for (let i = 1; i < arguments.length; i++) {
args.push('arguments['+i+']');
}
//下面代码中args 会自动调用 args.toString() 方法,因为'context.fn(' + args +')'本质上是字符串拼接,会自动调用toString()方法
var result = eval('context.fn(' + args +')');
//将前面对context额外添加的fn属性删掉
delete context.fn;
return result;
}
上面我们用比较老的方式实现了,下面我们尝试用es6的方式实现
Function.prototype.call = function(context){
context = context ? Object(context) : window;
context.fn = this;
let args = [...arguments].slice(1);
let result = context.fn(...args);
delete context.fn;
return result;
}
apply的实现跟call是差不多的,区别在于apply接收的参数是一个数组
//apply 的实现原理
Function.prototype.apply = function(context,args){
context = context ? Object(context) : window;
context.fn = this;
if(!args){
return context.fn();
}
//利用数组的toString特性
let result = eval('context.fn('+args+')');
delete context.fn;
return result;
}
最后我们还是用es6的方式简单实现一下
Function.prototype.apply = function(context,args){
context = context ? Object(context) : window;
context.fn = this;
if(!args){
return context.fn();
}
let result = context.fn(...args);
delete context.fn;
return result;
}