bind的实现原理

  //作用域问题
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }
      func();
    },
    c: 'hello'
  }
  a.b(); // undefined 这里的this指向的是全局作用域
  console.log(a.c); // hello
  
-----------------------------------------------------------------------------
// 使用bind方法一
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }.bind(this);
      func();
    },
    c: 'hello'
  }
  a.b(); // hello
  console.log(a.c); // hello
 ------------------------------------------------------------------------------
// 使用bind方法二
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }
      func.bind(this)();
    },
    c: 'hello'
  }
  a.b(); // hello
  console.log(a.c); // hello
  ---------------------------------------------------------------------
  // 分析:这里的bind方法会把它的第一个实参绑定给f函数体内的this,所以里的this即指向{x:1}对象;
  // 从第二个参数起,会依次传递给原始函数,这里的第二个参数2即是f函数的y参数;
  // 最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1+2+3=6
  // 分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)
  function f(y,z){
    return this.x+y+z;
  }
  var m = f.bind({x:1},2);
  console.log(m(3)); // 6
  -----------------------------------------------------------------
  绑定函数作为构造函数
  绑定函数也适用于使用new操作符来构造目标函数的实例。当使用绑定函数来构造实例,注意:this会被忽略,但是传入的参数仍然可用。
  function Point(x, y) {
    this.x = x;
    this.y = y;
  }
  Point.prototype.toString = function() { 
    return this.x + ',' + this.y; 
  };
  var p = new Point(1, 2);
  p.toString(); // '1,2'
  var emptyObj = {};
  var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
  // 实现中的例子不支持,
  // 原生bind支持:
  var YAxisPoint = Point.bind(null, 0/*x*/);
  var axisPoint = new YAxisPoint(5);
  axisPoint.toString(); // '0,5'
  axisPoint instanceof Point; // true
  axisPoint instanceof YAxisPoint; // true
  new Point(17, 42) instanceof YAxisPoint; // true
  上面例子中Point和YAxisPoint共享原型,因此使用instanceof运算符判断时为true。
  ---------------------------------------------------------------------
  // 实现预定义参数
  Array.prototype.slice.call(arguments)能将具有length属性的对象(类数组)转成数组
  function list() {
    return Array.prototype.slice.call(arguments);
  }
  var list1 = list(1, 2, 3); // [1,2,3]
// 第一个参数undefined表示this的指向,第二个参数10即表示list中真正的第一个参数,依次类推
  var a = list.bind(undefined, 10);
  var list2 = a(); // [10]
  var list3 = a(1, 2, 3); // [10,1,2,3]
  
 ------------------------------------------------------------
 首先我们可以通过给目标函数指定作用域来简单实现bind()方法:
 Function.prototype.bind = function(context){
    self = this;  //保存this,即调用bind方法的目标函数
    return function(){
      return self.apply(context,arguments);
    }
 };
 ------------------------------------------------------------
// 理解这里的context
  function getContext(context) {
      // context这里只管第一个参数
      console.log(context)
  }
  getContext('this', 'params1', 'params2') // 'this' 这里只管第一个参数
 
 考虑到函数柯里化的情况,我们可以构建一个更加健壮的bind():
 Function.prototype.bind = function(context){
    // var a = b.bind(context, params1, params2) 
    // 把arguments转换成一个数组,然后截取第一个以后的参数,第一个是context
    // 获取params1,params2
    var args = Array.prototype.slice.call(arguments, 1), 
    self = this;
    return function(){
      var innerArgs = Array.prototype.slice.call(arguments);
      var finalArgs = args.concat(innerArgs);
      return self.apply(context,finalArgs);
    };
};
这次的bind()方法可以绑定对象,也支持在绑定的时候传参。
--------------------------------------------------------------
继续,Javascript的函数还可以作为构造函数,那么绑定后的函数用这种方式调用时,情况就比较微妙了,需要涉及到原型链的传递:
Function.prototype.bind = function(context){
  var args = Array.prototype.slice(arguments, 1),
  F = function(){},
  self = this,
  bound = function(){
      var innerArgs = Array.prototype.slice.call(arguments);
      var finalArgs = args.concat(innerArgs);
      return self.apply((this instanceof F ? this : context), finalArgs);
  };
  F.prototype = self.prototype;
  bound.prototype = new F();
  retrun bound;
};
复制代码

转载于:https://juejin.im/post/5d2562c451882542cf101235

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值