js深入之call/apply/bind的模拟实现

前言

call,apply,bind这三个方法都是用来改变函数的this指向

call

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

模拟实现 

基本思想是把fn.call(obj,args)中的fn赋值为obj的属性

然后调用obj.fn即可实现fn中this指向的改变

    // call和apply实现方式类似,只是传参的区别
    //myCall函数的参数,没有传参默认是指向window
    Function.prototype.myCall = function (context = window) {
        context.fn = this //为对象添加方法(this指向调用myCall的函数)
        let args = [...arguments].slice(1) // 剩余的参数
        let res = context.fn(...args)  // 调用该方法,该方法this指向context
        delete context.fn //删除添加的方法
        return res
    }

测试

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.myCall(foo, 'bind1')

apply 

call和apply的功能相同,区别是传递函数参数的方式不同,call是一个一个传入,apply是通过一个数组传递 

模拟实现  

    Function.prototype.myApply = function (context = window) {
        context.fn = this;
        let args = arguments[1] // 剩余的参数
        let res = context.fn(...args);
        delete context.fn;
        return res;
    }

测试

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.myApply(foo, ['bind1'])

bind 

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

 bind的几个特性如下 :

  • 返回一个新的函数
  • 分段接收参数
  • 改变this指向
  • 返回的新函数可以使用new操作符

 arguments

想要实现模拟的话,我们还需要了解一下arguments对象。

arguments对象不是一个Array。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。可将arguments转换为:

// es5
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);

// es6
const args = Array.from(arguments);
const args = [...arguments];

模拟实现

    Function.prototype.myBind = function (context) {
        var self = this; // this 指向调用者
        var args = Array.prototype.slice.call(arguments, 1); //第二个参数
        var fNOP = function () { };
        var fBound = function () { //返回一个函数
            var bindArgs = Array.prototype.slice.call(arguments);//接受的参数
            // console.log(bindArgs);
            return self.apply(context, args.concat(bindArgs));
        }
        //当 bind 返回的函数作为构造函数的时候
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    }

测试 

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.prototype.friend = 'prop';
    let demos = demo.myBind(foo, 'bind1')
    let bar = new demos(35);
    console.log(bar.friend);

posted @ 2022-10-07 21:59  卟怪  阅读(15)  评论(0编辑  收藏  举报