this/call/apply/bind理解和原生实现

152 阅读3分钟

今天面了头条,心拔凉拔凉的,很多以为自己会的东西给别人描述的时候乱七八糟的,痛定思痛,决定以后隔一段时间写一篇文章,记录每天的学习情况。希望自己能坚持下来。 回忆起来,好像一切的不开心是从this开始的。

下面是我理解的this,希望各位大佬批评指正。

this是什么

this在ES5中永远指向调用它的那个对象。

ES6中虽然大家经常把箭头函数拿出来说事情,但是我认为只要记住关于箭头函数的一点就可以了。在判断this的指向时,将其看作普通的方法即可。普通的方法中的this指的是包含它的函数的this。这样一来就很清楚了。

call/apply是什么

this的指向可以通过调用对象的改变而改变,也可以通过call/apply来改变。

调用方法为Function.call(obj,...args)/Function.apply(obj,args)。它是说用obj这个上下文去调用Function。他们的区别在于args的类型。

原生实现call和apply

我们先来看看原来最简单的call是怎么调用的 func.call(obj)(obj可能为null)。

分析了之后来实现这个代码。

因为是某个函数要来调用这个方法,证明mycall方法应该是函数原型上的一个方法

Function.prototype.myCall = function(context){
    if(typeof context === 'object'){
        context = context?context:window ;//在没有传入context的情况下,默认应该是window
    }else{
        context = Object.create(null);//传入的context类型不对的情况下,应该创建对象
    }
    let func = this;//谁调用mycall这个函数,谁就是this
                   //其实讲来将去,就是执行func这个函数,只不过是用context这个对象去调用
    let fn = Symbol();//防止context对象以前有过fn这个属性
    context[fn] = func;//将func作为context这个对象的属性存储起来,去调用的时候this也就会指向context
    let args = [];
    for(let i=1;i<arguments.length;i++){   
        args.push(arguments[i]);
    }//如何接受调用时候的传参,还没有实现call,不能使用slice函数
    let result = context[fn](...args);//用context对象调用这个函数
    delete context[fn];//删除绑定在context上的属性
    return result;
}

myApply的实现和myCall的实现类似,只是传输参数的方式不同而已

Function.prototype.myApply = function(context){
    if(typeof context === 'object'){
        context = context?context:window ;//在没有传入context的情况下,默认应该是window
    }else{
        context = Object.create(null);//传入的context类型不对的情况下,应该创建对象
    }
    let func = this;//谁调用mycall这个函数,谁就是this
                   //其实讲来将去,就是执行func这个函数,只不过是用context这个对象去调用
    let fn = Symbol();//防止context对象以前有过fn这个属性
    context[fn] = func;//将func作为context这个对象的属性存储起来,去调用的时候this也就会指向context
    let args = arguments[1];//函数的输入参数是一个数组,包含了应该输入的参数
    let result = context[fn](...args);//用context对象调用这个函数
    delete context[fn];//删除绑定在context上的属性
    return result;
}

bind是什么

调用方法为func.bind(obj,[...args]),它会返回一个函数,这个函数是将obj绑定到func的this上之后返回的函数。

现在来看一下这个bind方法的调用 func.bind(obj),同样还是要在函数的原型上面写。

Function.prototype.myBind = function(context){
    let outArgs = Array.prototype.slice.mycall(arguments,1);//获取绑定时传入的参数
    let func = this;//记录应该执行的函数
    return function(){//bind函数返回一个参数
        let inArgs = Array.prototype.slice.mycall(arguments);
        let args = outArgs.concat(inArgs);//为了支持函数柯里化
        return func.myApply(context,args)
    }
}

我现在差不多就是这样理解的。 欢迎各位批评指正!!!