手撕apply,call和bind函数

684 阅读1分钟

什么是apply,bind,call

这三者的作用都是用来改变this指向的,我们实现源码也是为了了解他的底层原理,方便使用。

手撕apply

Function.prototype.apply(obj,arr){
    if(!obj){
       obj= typeof window==='undefined'?global:window;//判断环境是在浏览器还是在node环境下
    }
    obj.fn=this;
    let result=null;
    if(arr===undefined || arr===null){
        result=obj.fn(arr)
    }else{
        result=obj.fn(...arr)
    }
    delete obj.fn;
    return result
}

这里我们需要知道一点,在obj.fn=this这一步中为什么要创建一个obj的fn属性?

首先我们的目的是将this指向obj,所以我们将另外一个函数放在obj.fn中,

这样的话,fn中的this自然就指向obj了。最后将其指针转向result中,然后删除这个属性就可以达到目的了。

手撕call

Function.prototype.apply(obj,...arr){
    if(!obj){
        obj=typeof window === 'undefined' ?global:window;
    }
    obj.fn=this;
    let result=null;
    result=obj.fn(...arr)
    delete obj.fn;
    return result;
}

手撕bind

Function.prototype.bind = function (obj, ...arg) {
    if (!obj) {
        obj = typeof window === 'undefined' ? global : window
    }
    let self = this
    let args = arg

    function f() {}

    f.prototype = this.prototype
    let bound = function () {
        let res = [...args, ...arguments]
        let obj = this instanceof f ? this : obj
        return self.apply(obj, res)
    }
    bound.prototype = new f()
    return bound
}

关于node环境和浏览器环境

1,浏览器环境中的this指向window,node环境中的this指向global

2,在浏览器中不同的浏览器厂商提供了不同的浏览器内核,浏览器依赖这些内核解析js,但是不同内核之间有些许的差异,所以需要考虑浏览器的兼容性。

node是对v8引擎进行了一定的封装,他对一些特殊用例进行了优化,提供了替代的API,使得v8在非浏览器环境下运行的更好。

总结

v8引擎,有两个环境支持js的解析, 一个是node,一个是浏览器。