14

I noticed a weird thing in javascript. Consider the below:

var fn = ''.toUpperCase.call
console.log(typeof fn); // "function"
fn(); // Uncaught TypeError: `fn` is not a function

The above was executed on my Chrome's Developer Console. Version is 43.0.2357.81 m.

The typeof operator clearly shows that fn is a function, but the error suggests otherwise.

I've noticed that Function.apply shows at least some meaningful error message.

So, when is a function, not a function?

15
  • Please show how exactly you're calling fn. Commented Jun 2, 2015 at 12:00
  • 5
    I'm getting undefined is not a function when calling fn, not fn is not a function. Commented Jun 2, 2015 at 12:02
  • 2
    Sure. Still, please show a full example of what code produces what error. Commented Jun 2, 2015 at 12:03
  • 2
    Please clarify if consoele is a typo and edit if not Commented Jun 2, 2015 at 12:03
  • 2
    Firebug has a more insightful error message: TypeError: Function.prototype.call called on incompatible undefined. Basically call() needs to be called on an object (this), which is lost, being called outside the original statement. Commented Jun 2, 2015 at 12:05

3 Answers 3

20

Context in Javascript is always established by the way you call a function.

var fn = ''.toUpperCase.call

This assigns the prototype implementation of the call function to fn. If you now call fn(), there's no context to the call. call would try to invoke the function object it was associated with. However, that context is established at call time. Since you're not giving it any context at call time, some internal component of call is throwing an error.

You'd have to do this:

fn.call(''.toUpperCase)

That's right, you call the call function, establishing a context, namely the toUpperCase string function. In this specific case this would lead to another error inside toUpperCase, since it is not bound to a specific context. You'd need to establish that context explicitly as well:

var fn = ''.toUpperCase.call
fn.call(''.toUpperCase.bind(''))

Also see How does the "this" keyword work?

Sign up to request clarification or add additional context in comments.

3 Comments

so do you think, my answer is the answer to the linked question too?
@Amit Yeah, you're basically saying the same thing there.
Context in Javascript is always established by the way you call a function. Unless it's an arrow function, or the function has been bound.
3

deceze's answer is correct, I just want to explain it from a different point of view.

Your fn is a reference to Function.prototype.call which needs to be called with a function as its this reference, in this case, the context for call is String.prototype.toUpperCase, which was inherited through ''.toUpperCase

On top of that, String.prototype.toUpperCase also has to be called with a specific context, the string to upper case.

Here's another way to code what you wanted that may help you understand what is going on.

    var str = 'aaa';
    var upper = ''.toUpperCase;
    var fn = upper.call;
    // Now we have to specify the context for both upper and fn
    console.log( fn.call(function() { return upper.call(str)}) ); // AAA

In your example, fn() is attempting to call call but it's not specifying the context, which typically defaults to the window object but in this case it just makes it undefined, which triggers a weird error in Chrome (as you discovered), but Firefox is clearer about the problem,

TypeError: Function.prototype.call called on incompatible undefined

1 Comment

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
1

So, when is a function, not a function?

The function is a function, but you are not executing it correctly, as explained in comments and the answer by @deceze

I noticed a weird thing in javascript.

You seem confused by the message that you are getting in the environment in which you tested, the message is not strictly correct.

Uncaught TypeError: fn is not a function

The current stable version of chromium (40.0.2214.91 on my linux install, chrome fails to run on my hardware without making settings changes), chrome being the environment on which you tested, gives a seemingly more correct error message that makes more sense.

Uncaught TypeError: undefined is not a function

So, were you asking/wanting to ask a serious question or were you just poking a little fun at a mistake in a version of chrome?

3 Comments

40.0.2214.91 is not the current stable version of Chrome; 43.0.2357.81 is. The package source you're getting Chrome from is not up to date. Also, I'd just like to make the distinguishing point that (even if the OP knew the answer to this question before asking), wanting to create a repository of information about this very confusing error is far cry from "poking fun".
I've lots of other work to do rather than poking a little fun at chrome. And FYI, I came across this stuff while answering here and not everyone uses the chrome version you use(and I don't update chrome manually, it happens automatically) and thanks for your answer. Thanks for the comment above mine too.
On Fedora 19 it is 40.0.2214.91, which updates automatically using YUM from a package repository, I don't intend to build it myself (and I just remembered this is chromium rather than chrome). I understand that different OS's have different stable versions, and there are bound to be differences. Ok, you did not include that information in your question, so you were really trying to check that you have answered another question correctly? Or I still don't really understand what this question is or what kind of answer you are expecting?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.