Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

a is a function, then what `a.call.call` really do?

enter image description here

These codes are run on chrome devtool.

It seems like b.call(same as a.call.call) is calling the first argument, which is a function, then pass the second argument as this. If the first argument is not a function, then throw not a function error.

Can someone explain how <Function>.call.call work?

like image 983
tjfdfs Avatar asked Jan 21 '16 06:01

tjfdfs


2 Answers

Let me show you an example.

function a() { console.log(1) }

function b() { console.log(2) }

a.call(b)    // 1

a.call.call(b)    // 2

a.call.call.call(b)    // 2

Why?

We know a.call(b) means invoke a() with this value b.

So that a.call.call(b) means invoke Function.prototype.call() with this value b, same as Function.prototype.call.call(b).

But Function.prototype.call.call() is not an ordinary function Object. It can be invoked but it has no property. There's some unique rules to invoke it.

Function.prototype.call.call(a)    // 1

Function.prototype.call.call(b)    // 2

In fact, Function.prototype.call.call(b) is an Exotic Object, furthermore, a Bound Function Exotic Object.

  • [Specification] A bound function is an exotic object that wraps another function object.

  • [Specification] Calling a bound function generally results in a call of its wrapped function.

So that Function.prototype.call.call(a) simply means a().

a.call.call(x) means invoke x, that is, x().

  • [Specification] In Function.prototype.call(thisArg), if thisArg is undefined or null, it will be replaced by global object.

a.call.call() means a.call.call(undefined) means a.call.call(window) means invoke window.

Try to invoke window you'll get Uncaught TypeError: window is not a function, so try to invoke a.call.call() you'll get Uncaught TypeError: a.call.call is not a function.

Hope it helps.

like image 83
Toxni Lee Avatar answered Nov 11 '22 11:11

Toxni Lee


Starting from the basic stuff,

What is .call ? its a function available inside Function.prototype . So that it can be called on any function, thats exactly why you are able to call a.call.

Now, What does a .call do ? it sets this context on the function you called .call on. so in your case, when you call a.call it can set a this context on function a (through the first parameter you pass to the .call function).

what is this inside the .call function ? it is nothing but the function you called .call on(in your case a),
so for simplicity you assume, inside the .call it might be calling the function like this() (and that is nothing but calling a()) - so far so good

to your question

a.call.call

what is happening here ? the second .call (i am counting left to right) is calling first .call and setting this for the first .call, which is nothing but the first parameter, which is a function.

now first .call will call this() (remember this is set by the second .call and it is the first param you passed and this is a function).

i hope, i could explain what i intended to explain.

let me tell why you got confused with a.call.call . it is because you are thinking where did my function a gone in all this confusion ? which is actually not involved as soon as yo call second .call (here this to first .call is coming from second .call which makes your function a obsolete in this case )

in you case .call.call should have been called on Function.prototype or Object or any other function (remember .call is part of Function.prototype and can be called on any function)

so you should have done

Function.prototype.call.call(...)

or even

Object.call.call(...)

Now i was confused about these thing last week(not .call.call but .call.bind), i asked a question here, and somebody explained it to me in very detailed, you can find it HERE

i tried to answer from my understanding from the question i asked.

after all this is what SO is for

UPDATE:

you question "It seems like b.call(same as a.call.call) is calling the first argument, which is a function, then pass the second argument as this. If the first argument is not a function, then throw not a function error."

your assumption is correct here

like image 37
Oxi Avatar answered Nov 11 '22 13:11

Oxi