call、apply和bind常用来显示改变函数运行环境中的this指向,这几天突发奇想如果call.call、bind.bind和bind().band()会是怎样的结果,先记录一下,给出一下我现在认为的结论,后面有时间了,深入研究下。
公共
1 | function fn01 () { console.log('fn01:', this); } |
这其中定义了两个函数fn01和fn02以及一个对象,每个方法右面注释是执行主体和this指向。上面的几种是比较常见的情况。
call
1 | fn01.call(fn02); // fn01 fn02 |
从这开始是主要内容,第一句,是比较常见的方式,执行fn01,this指向改为fn02。
接着就是我的疑惑的地方:call.call
从结果上看,call.call
中间插入几个call并不影响最终结果。
注意看下这两句:
1 | fn01.call.call(fn02); // fn02 window |
按我现在的看法,fn01.call.call(fn02)
可能就相当于fn02.call()
。
这行代码的运行过程可能是这样:fn01.call执行了call方法,改变了fn01.call的this指向为fn02。但是fn01.call执行的this指向是fn01,所以最终执行主体就变成了fn02。这时候就相当于fn02.call()
,因为call没有参数,所以结果this指向了window。
这样看,fn01.call.call(fn02, fn02)
相当于fn02.call(fn02)
。所以最终结果,fn02是执行主体,this也指向了fn02。
后面加多少个call,原里应该都是一样的,所以不再赘述。
bind
1 | // bind |
bind有两种情况一种是bind.bind,一种是bind().bind()。
首先来看bind().bind(),无论链式多少个,实际上都以第一个bind()中的参数为准,原因可能是bind函数返回的函数中的this已经被外层的bind函数(第一个bind函数)确定,后面再进行bind操作传进来的参数没有做处理。但此原因暂时没有验证,仅作猜想。
接着是bind.bind,bind.bind可能和call.call类似,fn01.bind执行了bind方法,改变了fn01.bind的this指向为fn02。但是fn01.bind执行的this指向是fn01,所以最终执行主体就变成了fn02。这时候就相当于fn02.bind()
,因为bind没有参数,所以结果this指向了window。执行一次fn02.bind()
(也就是fn13),返回的函数执行后,就和call.call的结论类似,只是最后一次传参的方式不太一样。
以上所有结论仅是猜想,还需要从更加深入的研究this指向还有call、bind的机制,设计出合理的验证方式。因时间原因,先放一放。