JavaScript bind函数

原文出自冴羽博客


Javascript bind函数

  1. 什么是bind函数
    bind()方法会创建一个新函数,当这个新函数被调用时,bind()的第一个参数将作为它运行时候的this,之后的序列参数将会在传递的实参前传入作为它的参数。
    由此可以得出bind函数的两个特点:

    1. 返回一个函数
    2. 可以传参数
  2. 返回函数的模拟实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Function.prototype.bind1 = function(context){
    var self = this
    //返回一个函数
    return function(){
    //这里的self也就是bar,context指的是 obj
    return self.apply(context)
    }
    }
    var obj = {
    value: 1
    }
    function bar(){
    console.log(this.value)
    }
    //返回了一个函数
    var retFn = bar.bind1(obj)
    //执行这个函数 , 相当于 bar.apply(obj)
    retFn() // 1
  3. 传参的模拟实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    Function.prototype.bind1 = function(context){
    var self = this
    //获取到通过bind1 传递进来的第二个参数,也就是 name
    var args = Array.prototype.slice.call(arguments, 1);

    return function(){
    // 获取到返回函数调用时传递进来的参数 也就是 age
    var bindArgs = Array.prototype.slice.call(arguments);
    // 将两次获得到的参数 通过 concat函数合并到 bindArgs中
    bindArgs = args.concat(bindArgs)
    // self 这里指调用bind1的函数 bar,通过apply 将this指向了context也就是 obj,继而访问到value的值,并将参数打印出来
    return self.apply(context,bindArgs)
    }
    }
    var obj = {
    value: 1
    }
    function bar(name, age){
    console.log(this.value)
    console.log(name)
    console.log(age)
    }
    var retFn = bar.bind1(obj, 'blue');
    retFn(18);
    /* 1
    * blue
    */ 18
  4. 构造函数效果的模拟实现

    一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器,提供的this值被忽略,同时调用时的参数被提供给模拟函数。
    也就是说bind函数返回的函数作为构造函数的时候,bind时指定的this值会失效,但是传入的参数依然生效。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    Function.prototype.bind1 = function(context){
    var self = this
    var args = Array.prototype.slice.call(arguments, 1);
    var value = 'bind1Value'
    var bindFn = function(){
    //var value = 'bindFnValue' //this.value 会打印这个值

    //小问题:调用 bind 的不是函数咋办?
    if(typeof this !== 'function')
    throw new Error("Function.prototype.bind - what is trying to be bound is not callable");

    //优化添加的
    var FNOP= function(){}

    var bindArgs = Array.prototype.slice.call(arguments)

    bindArgs = args.concat(bindArgs);
    return self.apply(this instanceof bindFn ? this : context, bindArgs)
    }

    // 这里可以优化一下
    // bindFn.prototype = this.prototype;
    // return bindFn;
    //优化添加的
    FNOP.prototype = this.prototype;
    bindFn.prototype = new FNOP();
    return bindFn;
    }

    var value = 2;
    var obj = {
    value: 1
    }

    bar.prototype.friend = 'yellow';
    function bar(name, age){
    this.sex = 'boy'
    console.log(this) // bindFn {}
    console.log(typeof this) // object
    // console.log(this.value) // bindFnValue
    // 这里为undefined就是因为this被改变成了bindFn{}
    console.log(this.value) // undefined
    console.log(name) // blue
    console.log(age) // 18
    }
    // retFn 就是bar,retFn.prototype 就是bar.prototype
    var retFn = bar.bind1(obj, 'blue');

    var ret = new retFn(18);
    console.log(ret.sex); // boy
    console.log(ret.friend) // yellow