Let's start with this setup:
function fn() { console.log(this); }
var thisvalue = {fn: fn};
Now you surely understand that thisvalue.fn()
is a method call, and sets the logged this
value to the thisvalue
object.
Next, you seem to know that fn.call(thisvalue)
does exactly the same call. Alternatively, we could write (thisvalue.fn).call(thisvalue)
(parentheses just for structure, could be omitted) as thisvalue.fn === fn
:
thisvalue.fn(…); // is equivalent to
(thisvalue.fn).call(thisvalue, …); // or:
(fn).call(thisvalue, …);
OK, but fn.call(…)
is just a method call as well - the call
method of functions is called on the fn
function.
It can be accessed as such because all function objects inherit this .call
property from Function.prototype
- it's not an own property like .fn
on the thisvalue
object. However, fn.call === Function.prototype.call
is the same as thisvalue.fn === fn
.
Now, we can rewrite that method call of .call
as an explicit invocation with .call()
:
fn.call(thisvalue); // is equivalent to
(fn.call).call(fn, thisvalue); // or:
(Function.protoype.call).call(fn, thisvalue);
I hope you spot the pattern and can now explain why the following work as well:
Function.prototype.call.call.call(Function.prototype.call, fn, thisvalue);
var call = Function.prototype.call; call.call(call, fn, thisvalue);
Breaking this down is left as an exercise to the reader :-)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…