call
功能
模拟前首先搞清楚call方法的功能:
- 改变调用函数的this指向
- 可传入多个参数:func.call(context, arg1, arg2…)
- 立即执行调用函数
不传参
function Fn() {
console.log(this.name);
this.name = "fan01"
console.log(this.name);
}
const o = {
name:"fan02"
}
Fn.call(o)
// fan02
// fan01
传参
var number = 2;
var obj ={
number:1
}
function Fn(name,age) {
console.log(this.number,name,age);
}
Fn.call(obj,"fan","18")
// 1 'fan' '18'
模拟
call方法 与 将函数当作对象的方法来调用 十分相似(如下)
// 测试一下
var number = 2;
var obj = {
number: 1,
test: function () {
console.log(this.number);
}
}
obj.test(); // 1
这里的this就指向了obj。
通过上面这个例子,我们可以将调用函数当做上下文对象的方法调用,那么this便会指向上下文对象:
Function.prototype.call2 = function (context){
// 获取调用的函数,这里的this指向调用 call方法的函数
var self = this;
//将调用的函数当作上下文对象的属性
context.fn = self;
//执行调用函数
context.fn();
//执行后删除context上的该函数属性(fn()) ,因为其是函数新增的一个属性
//并不是原先上下文中的原始属性,所以需要删除
delete context.fn
}
// 测试
var number = 2;
var obj = {
number:1
}
function a(){
//注意这里输出 number 与 this.number结果不同
console.log(this.number);
}
a.call2(obj)
// 1
接下来实现传入参数:
Function.prototype.call2 = function (context,...args){
// 获取调用的函数,这里的this指向调用 call方法的函数
var self = this;
//将调用的函数当作上下文对象的属性
context.fn = self;
//执行调用函数(这里传入了参数)
context.fn(...args);
//执行后删除context上的该函数属性(fn()) ,因为其是函数新增的一个属性 并不是原先上下文中的原始属性,所以需要删除
delete context.fn
}
// 测试
var number = 2;
var obj = {
number:1
}
function a(name,age){
//注意这里输出 number 与 this.number结果不同
console.log(this.number,name,age);
}
a.call2(obj,"fan","12")
// 1 'fan' '12'
完善call2方法
- 调用函数的需要返回值
- 传入的上下文不是引用类型
- 传入的上下文为null或者undefined,this会指向window
Function.prototype.call2 = function (context,...args){
//对传入的上下文进行包装
context = new Object(context|| window);
console.log(context);
// 获取调用的函数,这里的this指向调用 call方法的函数
var self = this;
//将调用的函数当作上下文对象的属性
context.fn = self;
//打印对象新结构(用于传入的上下文不是引用类型时)
console.log(context);
//执行调用函数
var res = context.fn(...args);
//执行后删除context上的该函数属性(fn()) ,因为其是函数新增的一个属性 并不是原先上下文中的原始属性,所以需要删除
delete context.fn
return res;
}
// 测试
var number = 2;
var obj = {
number:1
}
function a(name,age){
return {
number: this.number,
name,
age
};
}
console.log(a.call2(obj, '张三', 12)); // {"number":1,"name":"张三","age":12}
console.log(a.call2(null, '张三', 12)); // {"number":2,"name":"张三","age":12}
console.log(a.call2(undefined, '张三', 12)); // {"number":2,"name":"张三","age":12}
//传入上下文不是引用类型 this为underfined
console.log(a.call2(1, '张三', 12)); // {"number":undefined,"name":"张三","age":12}
// Number {1, fn: ƒ} Number 对象内没有number
console.log(a.call2('1', '张三', 12)); // {"number":undefined,"name":"张三","age":12}
apply
apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数 我们将方法一修改一下
Function.prototype.apply2 = function (context,args){
//对传入的上下文进行包装
context = new Object(context|| window);
console.log(context);
// 获取调用的函数,这里的this指向调用 call方法的函数
var self = this;
//将调用的函数当作上下文对象的属性
context.fn = self;
//打印对象新结构(用于传入的上下文不是引用类型时)
console.log(context);
//执行调用函数
var res = context.fn(...args);
//执行后删除context上的该函数属性(fn()) ,因为其是函数新增的一个属性 并不是原先上下文中的原始属性,所以需要删除
delete context.fn
return res;
}
// 测试
var number = 2;
var obj = {
number:1
}
function a(name,age){
return {
number: this.number,
name,
age
};
}
console.log(a.apply2(obj, ['张三', 12])); // {"number":1,"name":"张三","age":12}
console.log(a.apply2(null, ['张三', 12])); // {"number":2,"name":"张三","age":12}
console.log(a.apply2(undefined, ['张三', 12])); // {"number":2,"name":"张三","age":12}
//传入上下文不是引用类型 this为underfined
console.log(a.apply2(1, ['张三', 12])); // {"number":undefined,"name":"张三","age":12}
// Number {1, fn: ƒ} Number 对象内没有number
console.log(a.apply2('1', ['张三', 12])); // {"number":undefined,"name":"张三","age":12}