解读Javascript中的Function.prototype.bind

首先贴上MSDN上标准的Polyfill:

 1 if (!Function.prototype.bind) {
 2   Function.prototype.bind = function(oThis) {
 3     if (typeof this !== 'function') {
 4       // closest thing possible to the ECMAScript 5
 5       // internal IsCallable function
 6       throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
 7     }
 8 
 9     var aArgs   = Array.prototype.slice.call(arguments, 1),
10         fToBind = this,
11         fNOP    = function() {},
12         fBound  = function() {
13           return fToBind.apply(this instanceof fNOP
14                  ? this
15                  : oThis,
16                  aArgs.concat(Array.prototype.slice.call(arguments)));
17         };
18 
19     if (this.prototype) {
20       // Function.prototype doesn't have a prototype property
21       fNOP.prototype = this.prototype; 
22     }
23     fBound.prototype = new fNOP();
24 
25     return fBound;
26   };
27 }

下面将上述代码逐行分析。

第一行判断Function的原型中是否有该函数, 因为bind函数并不是每个浏览器都支持,下面列出浏览器的支持情况:

 

  

第3行 if (typeof this !== 'function')用来判断调用bind函数的对象是否为函数,注意在整个bind函数作用域中this指代调用它的对象,且该对象必须为函数,通过typeof函数来检测。

第9行var aArgs = Array.prototype.slice.call(arguments, 1)中,arguments为传入bind函数的参数对象,由于其并不是数组,而是一种伪数组对象,但是可以使用数组的slice方法,由于bind函数的第一个参数为绑定的函数,故slice方法从1开始获取参数。  

  举例: someFunc.bind(oThis, arg1, arg2) ,则slice方法取到的就是[arg1, arg2]。

第12行fBound函数,为最终bind函数返回的新函数,通过apply方法将fToBind函数的上下文改为oThis。

第16行 aArgs.concat(Array.prototype.slice.call(arguments))),这行代码将bind函数中的参数和执行bind函数返回的函数传入的参数进行合并,最终传给实际调用的函数fToBind来使用。

第21行 fNOP.prototype = this.prototype; 将fToBind中的原型对象赋给一个没有原型的空函数,再通过fBound.prototype = new fNOP(); 进行原型函数继承,因为apply方法只能继承构造方法,最终返回的fBound匿名函数继承了fToBind对象的构造方法和原型方法,且上下文为oThis,从而实现了绑定。

实际上 anotherFunc =someFunc.bind(oThis, arg1, arg2);中的anotherFunc即为fBound, anotherFunc(args)即执行fBound(args)。 

posted @ 2017-05-04 21:05  虹夜  阅读(1519)  评论(0编辑  收藏  举报