call、apply 一般用来改变 this 的指向。手动实现call,apply核心就是改变函数内部的this指向。

实现call

实现思路:改变this指向,将目标函数作为对象的属性,利用arguments数组对象获取传入的参数,删除该函数

var obj = {
     value :1,
};
function func(){
    console.log(this.value);
}

Function.prototype.myCall = function(context) {
     context =  context || window;
        context.fn = this;//将函数作为对象的一个属性传入
        context.fn();
        delete context.fn;//删除该函数
}

下面来看一下有参数执行时的代码
和上面相比只是加入了arguments处理了一下传入的参数

var obj = {
     value :1,
};
function func2(name,age) {
  console.log(this.value);
  console.log(name);
  console.log(age);
}
Function.prototype.myCall = function(context) {
     context =  context || window;  //如果当前传入的值为空,指向window
        context.fn = this;//将函数作为对象的一个属性传入
        var args = [];//执行该函数
        for (var i =1; i< arguments.length;i++ ){//获取传入的对象和参数值
                args.push('arguments[' + i + ']') //注意,只能存入argument[1],argument[2]的形式,存入原始数据会报错
        }
         eval('context.fn(' + args +')');//拼凑执行该函数,同等于func("abc",23)

        delete context.fn;//删除该函数
}

实现apply

call的不同点,就是argument换成了arr数组

var obj = {
     value : 1
}
function  func(name, age) {
    console.log(this.value);
    console.log(name);
    console.log(age);
}
var arr = ["abc", 23]
func.apply(obj,arr);

Function.prototype.myApply = function (context, arr) {
    context = context || window;
    context.fn = this;
    if (!arr) {
        context.fn();
    } else {
        var args = [];
        for (var i = 0; i<arr.length; i++) {//传入的数组进行处理
            args.push('arr['+i+']');
        }
        eval('context.fn('+args+')');//等同于,func("abc",23)

    }
    delete context.fn;
}
最后修改:2019 年 09 月 20 日
如果觉得我的文章对你有用,请随意赞赏