【js高级篇】手写call apply bind源码 超级详细

一.Function.prototype.call()

语法:

function.call(thisArg, arg1, arg2, ...)

实现功能:

改变调用者function的this指向,指向call的第一个参数,并且接收剩余参数,同时调用function

call的源码

主要用到了arguments接收实参和 "... ” ---展开符传参

 Function.prototype.mycall = function() {
          /*
            用arguments接收实参
          传入的参数为真值就返回这个参数,为null/undefind/其他假值 则指向window  
          短路运算
           */
            var paramFirst = arguments[0] || window;
         /*
          接收剩余参数
          将伪数组aruments转换成真数组,调用数组方法,切割数组,得到剩余参数
            */
          var _arg = Array.from(arguments).slice(1);
          //this指向调用者,如下面实例,指向demo
          paramFirst.fn = this;
         //调用这个函数即demo函数体
         paramFirst.fn(..._arg);//...是es6中的展开语法,将数组中的值依次传入
         /*
        删除paramFirst中添加的fn,
        是为了让paramFirst本身不产生额外的fn,
        外层也调用不了fn,以免产生多余的影响
            */
            delete paramFirst.fn

        }

        function demo(a,b) {
            console.log(this);
            console.log(a+b)
        }
        var obj = {
            name: "张三",
            age: 18
        }
        demo.mycall(obj, 1, 2);

二.Function.prototype.apply()

语法:

func.apply(thisArg, [argsArray])

实现功能:

改变调用者function的this指向,指向aplly的第一个参数,并且接收剩余参数,同时调用function

与call的唯一不同就是,剩余参数是以数组形式传递

apply的源码

主要用到了arguments接收实参,具体代码和call大同小异

 Function.prototype.myApply = function() {
            var target = arguments[0] || window;
            var _arg = arguments[1];
            target.fn = this;
            target.fn(..._arg);
            delete target.fn
        }

        function demo(a,b) {
            console.log(this);
            console.log(a+b)
        }
        var obj = {
            name: "张三",
            age: 18
        }

        demo.myApply(obj, [1, 2]);

三.Function.prototype.bind()

语法:

function.bind(thisArg[,arg1[,arg2,arg3]]

实现功能:

改变调用者function的this指向,指向bind的第一个参数,并且接收剩余参数.

并返回一个新的函数,新函数接收调用者的所有剩余参数

bind的源码

主要用到了arguments接收实参,和数组concat()方法,slice()方法。

并且考虑到了调用者如果是new 构造函数的特殊情况,因为new会改变this指向。

Function.prototype.mybind = function() {
            var param1 = arguments[0] || window;
            var that = this
            var _arg = Array.from(arguments).slice(1);
            //返回一个新函数
            return function() {
             var array =  _arg.concat(Array.from(arguments));
            //用new.target判断调用者是否为new 构造函数的对象
                if (!new.target) {
                    param1.fn = that;
                   
                    param1.fn(...array);
                    delete param1.fn;
                } else {
                    return new that(...array);
                }

            }

        }
  function Person(name) {
            this.name = name
        }
        var obj = new Person("张三");

        function add(a, b) {
            console.log(this)
            console.log(a + b)
        }
    //bind三种传参情况
        add.mybind(obj, 1, 2)()
        add.mybind(obj, 1)(2)
        add.mybind(obj)(1, 2);

这个记录下来为了方便以后使用的方便,也希望大佬们多多交流,多多留言,指出我的不足的之处啦!

有需要的小伙伴可以研究研究啦!!

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值