理解bind的实现原理
09 Mar 2017
感觉应该坚持一个月至少产出一篇博客文章来, 碰巧在sf看到一个关于bind
的问题,又回到去年看过MDN关于bind实现的polyfill,当时看得一脸懵逼,如今对原型链使用有进一步的认识了,于是记一下笔记(原来之前没做笔记)并总结一下。
首先关于bind
的使用,就是将函数转变为一个新的函数,而这个新的函数在调用过程中,自带bgm,哦不,自带指定的this
。
我们知道,一个函数里,有两个很重要的概念,一个是arguments
函数参数对象,另外一个就是this
,指向函数所属对象。
当我们声明一个函数时,在调用过程中,内部this
往往指向于window
(浏览器环境下),因为这个函数作为普通函数被直接调用时,属于全局调用,所以此时它的this
指向全局对象即window
. PS: 虽然我更想理解成普通函数a,可以用window.a
来理解,但是如果是在自执行函数里面声明的function,对不起,它不在window里,所以这样理解无效。
而如果是一个对象里的函数,在调用这个对象调用自己成员函数的时候,其this
指向于自己,但如果单独把这个函数抽离过来使用,this
又不一定指向原来的对象了。
此时,bind
就是意在让function
自带this
的神器。
看起来bind
很强大,但是低版本浏览器,特别是ie9-,就没有bind
这个方法。
没事,没轮子我们自己造,我们可以通过给Function
原型加上bind
属性方法来实现,运用currying的方式(生成一个新函数)、闭包和apply
来实现this
的绑定。
同时,我们要考虑到当原函数作为构造函数来使用,bind
产出的函数也当构造函数来new
的时候,需要忽略绑定的this
了,也就是bind
的原始作用移除。
来看一下MDN
的polyfill实现:
按顺序看,首先第一点就是判断是否有bind
了,如果有,就没下面什么事了(这么快就领便当)。
最外层的function内,this
指向的即原函数本身,那么首先会判断这个原函数是不是可执行的,如果不是,bind了也没意义,于是报错。有点疑惑,既然都能访问到Function.prototype
了,这个原函数难道还不是function
么?这个问题这里有解答
其实就是这样:
间接的通过call
或者apply
来调用bind
时,内部this
指向了notAFunction
了!!!
后面变量分析:
aArags
主要用于把bind时剩余的参数作为补充参数,在调用新函数时整合参数来调用。
fToBind
为原函数,fNOP
为中介,一个纯函数,并且在第19行处将其原型链指向到原函数的原型链,这个干吗用呢?
fBound
就是新函数了,它其实内部是调用fToBind
,并且绑定了this
,并返回执行结果。
而在this
的选取中,通过判断 原函数是否为fNOP
实例来决定用this
还是绑定指定对象。
fBound.prototype = new fNOP();
这句使得,当new fBound()
即new调用新函数时,其this
即为fNOP
的实例,从而达到新函数作为构造函数调用时,无视原来要绑定的this
.
再回过头来,看看关于fNOP.prototype = this.prototype;
,因为最后fBound
的原型链指向fNOP
的实例,而fNOP
的原型链又指向原函数的原型。 如此一来,当新函数产生的实例对象,也能访问到原函数的原型链去了。
具体例子如下:
如果原函数没有更多的原型链指向,直接新函数构造的实例是可以访问到原函数内的属性的,但是如果原函数还有其他原型指向,要想访问原型链上的属性,那bind的实现里就必须带上原函数的原型链处理。
这个bind
实现基本满足了要求,还有其他更佳兼容的,可读从一道面试题的进阶,到“我可能看了假源码”(2)