1

This is true (run it in the console in Google Chrome):

typeof String.call.call === 'function'

But calling it as String.call.call() throws an error saying it's not a function:
Uncaught TypeError: String.call.call is not a function at :1:13

Why trying to call a function (as per its typeof definition) throws an error saying it's not a function? Is it actually a function or not?

Note this happens to other classes such as Number, Function or others that inherit the .call method.

XCS
  • 27,244
  • 26
  • 101
  • 151
  • 2
    `var call = Function.call; call();` fails for the same reason. Before someone answers, can you see why now? – Patrick Roberts Jun 12 '17 at 20:54
  • @PatrickRoberts That is the same issue, but written on two lines, I still fail to see why something whose type is `function` is treated as `not a function` when evaluated. – XCS Jun 12 '17 at 20:57
  • 1
    Imagine in C you declare a void pointer without initializing it, typecast it to some kind of function and then try to execute it. Same thing, basically. Point is, _what_ are you calling, exactly? Who knows, but likely there's no function there. – Patrick Roberts Jun 12 '17 at 20:58
  • 1
    I think I understand, it's just probably Chrome that throws a "bad" error code, I see trying the same thing in IE or FireFox leads to different (more logic) errors. – XCS Jun 12 '17 at 21:01

1 Answers1

1

Let's try to break this down into more manageable pieces.

String is a constructor (or a static function / constructor hybrid, whatever you want to call it), and as such, it inherits from Function.prototype, because it is a function.

call is a function that executes its context (the this) with the context given to it in the first parameter:

console.log(String.call(true));
console.log(Array.call(null));
console.log(Function.call('so?'));
console.log(Object.call(/notice me/));

Let's look at a more official definition for Function.call():

The call() method calls a function with a given this value and arguments provided individually.

function.call(thisArg, arg1, arg2, ...)

Now, the interesting part here is noting that these three are identical:

'use strict';

var callRef = String.call; // Function.call, Array.call, Boolean.call, all of them are ===

console.log(String(/make me into a string/));
console.log(String.call(undefined, /make me into a string/));
console.log(callRef.call(String, undefined, /make me into a string/));

The callRef.call(String) means, call callRef() with the context of String, which is to say, execute String() with the context and parameters provided in the following arguments.

As we recall, the context doesn't really matter, but now we know that the first parameter of callRef.call() does matter, because it determines what function to execute, because it's telling callRef() what its context is, which gets executed as a function with the context provided in the next parameter.

Now reflecting on the initial question, what happens when we attempt to execute String.call.call()? Well, if a parameter is not specified, it is undefined, and we know that typeof undefined !== 'function'.

So here's my final answer:

String.call.call() is indeed a function... but all it's doing is attempting to execute undefined as a function, which obviously isn't.

String.call.call();

I hope this has been an interesting and informative explanation.

Community
  • 1
  • 1
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153