美文网首页
javascript bind函数的实现

javascript bind函数的实现

作者: Weastsea | 来源:发表于2020-05-17 18:34 被阅读0次

    既然讲到bind,我们就不得不说call 和 apply 。在Javascript中,涉及到函数式语言风格的代码,都离不开call 和apply。那么我们在讲bind之前,就先好好分析一下call 和 apply。

    callapply 方法是ECMAScript 3 给Function 的原型定义的2个方法。分别是Function.prototype.call 和 Function.prototype.apply。

    1: call 和apply 的作用

    call 的mdn定义: call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

    apply的mdn定义:apply()方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象提供的参数

    通过以上的定义,我们可以看出,call 和 apply 的相同点都是执行一个函数,并指定this。
    唯一的区别就是:

    • apply 函数第二个参数为一个带下标的集合,这个集合可以是数组,也可以是类数组。apply 把这个集合中的元素作为参数传递给被调用的函数。
    • call 函数的参数数量不固定,从第一个参数以后, 每一个参数被依次传入函数。

    请看下面2个🌰

    var func = function (a,b,c) {
     console.log([a,b,c]) // 输出 [1,2,3]
    }
    
    func.apply(null, [1,2,3])
    
    var func = function (a,b,c) {
      console.log([a,b,c]) // 输出[1,2,3]
    }
    func.call(null, 1,2,3)
    

    其实Javascript参数在内部就是用一个类数组来表示的。我们可以通过arguments类数组来接受。call其实是包装了apply上的一个语法糖。如果我们明确的知道函数接受多少个参数,而且想一目了然的表达形参和实参的对应关系,可以使用call 来传递参数。
    有一点需要注意的是:当使用call 或apply时,第一个参数为null, 函数体内的this会指向默认的宿主对象。

    // 在浏览器环境下
    var func = function (a,b,c) {
      console.log(this === window)  // true
    }
    func.apply(null, [1,2,3])
    
    Math.min.apply(null, [1,2,3,34,4]) // 1
    

    2: 说清楚apply和call ,我们开始讲讲bind。

    bind 用来改变this的指向,并返回一个改变了this指向的新函数。
    我们首先实现一个比较简单的bind。

    Function.prototype.bind = function (context) {
      // this  指的是需要绑定的函数
      let self = this
      return function () {
        // context 指需要绑定的this
        return self.apply(context, arguments)
       }
    }
    

    来一个🌰演示一下

    let obj = {name: 'jack'}
    
    var func = function () {
      console.log(this.name) // jack
    }.bind(obj)
    
    func() 
    

    以上代码的实现原理是,我们先把func函数的引用保存了起来。然后返回一个新函数。当我们将来执行func函数时。实际上是执行这个返回的新函数。在新函数内部,我们执行了self.apply(context, arguments)这一句才是执行了原来func函数。并指定了context为func函数体内的this。

    说清楚了原理,我们实现一个更完善的bind实现:

    Function.prototype.bind  = function () {
     let self = this
      // 获取bind第一个参数,即需要绑定的对象。
     context = [].shift.call(arguments)
     // 获取bind剩余的参数,并转换为数组
     args = [].slice.call(arguments)
     // 返回一个函数,当执行的时候,执行self.apply
     return function () {
         // arguments 是执行返回的函数时,传入的参数。
         return self.apply(context, [].concat.call(args, [].slice.call(arguments)))
     }
    }
    

    我们再给一个🌰演示下:

    var obj = {
     name: 'jack',
    }
    var func = function (a,b,c,d) {
     console.log(this.name) // jack
     console.log([a,b,c,d])  // 输出 [1,2,3,4]
    }.bind(obj, 1,2)
    
    func(3,4)
    

    我们用es6 来改造下这个写法:

    Function.prototype.bind  = function (context, ...res) {
      let self = this
       // 获取bind第一个参数,即需要绑定的对象。
      context = context
      // 获取bind剩余的参数,并转换为数组
      args = res
      // 返回一个函数,当执行的时候,执行self.apply
      return function () {
          // arguments 是执行返回的函数时,传入的参数。
          return self.apply(context, [...args, ...arguments])
      }
    }
    
    

    几行代码就可以解决,是不是简洁了许多😄

    相关文章

      网友评论

          本文标题:javascript bind函数的实现

          本文链接:https://www.haomeiwen.com/subject/vfmsohtx.html