JavaScript学习笔记

bind()使用场景及原理

2018-04-02  本文已影响0人  小二子SAMA

bind()的语法是:

    fun.bind(thisArg[, arg1[, arg2[, ... ]]]);

thisArg:当绑定函数被调用时,该函数会作为原函数运行时的this指向,当使用new操作符调用绑定函数时,该参数无效。

arg1, arg2... :当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。

返回值:返回由指定的this值和初始化参数改造的原函数拷贝。

bind()使用场景:

1)作为绑定函数使用,并且设置函数的this值。


````

var name = "The Window";

var object = {

    name : "My Object",

    getNameFunc : function() {

        return function(){

            return this.name;

        }

    }

}

console.log(object.getNameFunc()());//>The Window

````

getNameFunc()返回一个匿名函数,object.getNameFunc()()立即调用它返回的函数,匿名函数的执行环境具有全局性,因此其this对象通常指向window。

为解决上面方法,我们可以把外部作用域中的this对象保存在闭包函数能够访问到的变量里:


````

var name = "The Window";

var object = {

    name : "My Object",

    getNameFunc : function() {

        var _this = this;

        return function(){

            return _this.name;

        }

    }

}

console.log(object.getNameFunc()());//>My Object

````

当然也可以bind()方法:


````

var name = "The Window";

var object = {

    name : "My Object",

    getNameFunc : function() {

        return function(){

            return this.name;

        }.bind(this)

    }

}

console.log(object.getNameFunc()());//>My Object

````

上面通过bind()方法实现的绑定,效果等价于如下:


````

var name = "The Window";

var object = {

name : "My Object",

getNameFunc : function() {

return function(){

return this.name;

}.apply(this)

}

}

console.log(object.getNameFunc());//>My Object

````

2) 偏函数,使一个函数拥有预设的初始值,也称柯里化(currying)


````

var sum = function(x, y) {return x + y;};

var succ = sum.bind(null, 1);//创建一个类似sum的新函数,this值设为null,指向全局变量

//第一个参数绑定到1,新的函数期望只传入一个实参

succ(2);//>3

````

3)配合setTimeout()使用


````

function LateBloomer() {

  this.petalCount = Math.ceil(Math.random() * 12) + 1;

}

// Declare bloom after a delay of 1 second

LateBloomer.prototype.bloom = function() {

//如果不使用bind()绑定作用域,作用域为winidow

  window.setTimeout(this.declare.bind(this), 1000);

};

LateBloomer.prototype.declare = function() {

  console.log('I am a beautiful flower with ' +

    this.petalCount + ' petals!');

};

var flower = new LateBloomer();

flower.bloom();  

````

4) 作为构造函数的绑定函数,即通过new关键字调用bind()产生的绑定函数,bind()中俄第一个参数(指定this值的参数)不起作用,后续参数正常使用。


````

function Person(_age, _address) {

this.age = _age;

this.address = _address;

console.log(this.name);//undefined

console.log(this.age);//23

}

var north = {

name : "north"

}

var northBind = Person.bind(north, 24);

var northObj = new northBind();

````

name并不是north对象含有的名字,可见第一个参数并没有起作用。

bind()的原理是:


````

if (!Function.prototype.bind) {

  Function.prototype.bind = function(oThis) {

    if (typeof this !== 'function') {

      // closest thing possible to the ECMAScript 5

      // internal IsCallable function

      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');

    }

    var aArgs  = Array.prototype.slice.call(arguments, 1),

        fToBind = this,

        fNOP    = function() {},

        fBound  = function() {

          return fToBind.apply(this instanceof fNOP

                ? this

                : oThis,

                 // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的

                aArgs.concat(Array.prototype.slice.call(arguments)));

        };

   // 维护原型关系

    if (this.prototype) {

      // Function.prototype doesn't have a prototype property

      fNOP.prototype = this.prototype;

    }

    fBound.prototype = new fNOP();

    return fBound;

  };

}

````

看这段代码需要注意的的几个点:

1. bind()返回值是改造参数后的原函数的拷贝,所以调用bind()的必须是函数;

2. 如果返回的函数是一个构造函数,那么this不改变,即不会被传入的第一反应参数重写。

3. fBound函数中对arguments的操作,其实是对bind()函数返回的绑定函数的参数的操作,aArgs和arguments的合并实现了参数预设功能。

4. bind()函数返回的绑定函数与最开始的原函数具有相同的原型

bind()和apply()、call()的区别:

bind()返回一个绑定函数,apply()、call()是立即调用原函数。

备注:可能还是没有完全理解bind吧。。。

参考:

Function.prototype.bind()

上一篇 下一篇

猜你喜欢

热点阅读