10

I know this is probably the second most asked-about thing in javascript, right after floating point arithmetic.

I generally know how this works, and how it's affected by arrow functions, .call(), .apply(), and .bind(). I thought I understood everything about it. But I do not.

In a web browser, document.createElement("div").classList.add("c") yields undefined as expected. However, this expression surprisingly is an error.

(true && document.createElement("div").classList.add)("c")

I expected it to be the same, but it's

Uncaught TypeError: Illegal invocation
    at <anonymous>:1:54
recursive
  • 83,943
  • 34
  • 151
  • 241
  • What is purpose of expression and call `(true && document.createElement("div").classList.add)("c")`? – guest271314 Mar 31 '17 at 06:36
  • 3
    In my understanding, its got to do with `()`. When you write anything inside `()`, it becomes an expression and they have their own context. So when you try to evaluate `.add`, the context of element has been destroyed and hence error – Rajesh Mar 31 '17 at 06:37
  • 2
    @guest271314 It makes the function call indirect. See http://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript – JJJ Mar 31 '17 at 06:38
  • @guest271314: The purpose of the expression is to illustrate the question. – recursive Mar 31 '17 at 06:38
  • Perhaps not certain what you are trying to achieve? Call `.add()`? – guest271314 Mar 31 '17 at 06:40
  • @JJJ For what purpose? – guest271314 Mar 31 '17 at 06:41
  • @Anil: I assume you mean "undefined". If it is undefined, then why did the first call succeed? – recursive Mar 31 '17 at 06:42
  • 2
    @guest271314: This is the minimum code that expresses the question. I adapted it from real application code, but this is not real application code. This code exists only to illustrate the question. – recursive Mar 31 '17 at 06:43
  • @recursive, i got it, later i removed my comment :) – Anil Mar 31 '17 at 06:44
  • @recursive Still not certain what you are trying to achieve by using the pattern? What is expected result? – guest271314 Mar 31 '17 at 06:45
  • @recursive, function add is expecting native code function `add() { [native code] }` – Anil Mar 31 '17 at 06:47
  • @guest271314: I'm trying to understand javascript. I expect the two statements to work the same way. – recursive Mar 31 '17 at 06:47
  • @Anil: `add()` isn't expectign native code. It *is* native code. – recursive Mar 31 '17 at 06:48
  • @recursive Does `var el = document.createElement("div"); el.classList.add("c");` not yield expected result? Why is the pattern at Question necessary? – guest271314 Mar 31 '17 at 06:49
  • @guest271314: Your code does yield the expected result. The code in the question is necessary to illustrate the question. If I changed it to your code, it wouldn't support the question. The code exists *only* to illustrate the question. – recursive Mar 31 '17 at 06:52
  • @recursive Am trying to understand Question. Have re-read, will re-read again. – guest271314 Mar 31 '17 at 06:54
  • @recursive If you chain `.classList.add("c")` to expression `undefined` is result `(true && document.createElement("div")).classList.add("c")`, `(true && document.createElement("div"))["classList"]["add"]("c")` though not sure if chaining to `()` is part of Question? – guest271314 Mar 31 '17 at 07:06

3 Answers3

5

Your statement

(true && document.createElement("div").classList.add)("c") can also be rewritten as following:

var add = (true && document.createElement("div").classList.add)
add("c")

[Logical AND (&&) expr1 && expr2 : Returns expr1 if it can be converted to false; otherwise, returns expr2.]

You see that function add is now part of window and loses reference of actual classList object and hence cannot be called correctly.

add's this now points to global object.

If you do following (if the new div is the only div on your page), it again has reference to the original object:

(true && document.createElement("div").classList.add).bind(document.getElementsByTagName("div")[0].classList)("c")
pranavjindal999
  • 2,937
  • 2
  • 26
  • 35
  • How do you know it can equivalently be re-written that way? That's not obvious to me. – recursive Mar 31 '17 at 06:44
  • that is not exactly equivalent, and was rewritten to explain your query, – pranavjindal999 Mar 31 '17 at 06:45
  • Logical AND (&&) expr1 && expr2 : Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false. so using ```&&``` in your statement is like extracting function from ```classList``` object and then calling the orphan function – pranavjindal999 Mar 31 '17 at 07:08
3

This will work, as it is returning this as classlist context

(document.createElement("div").classList.add)("c")

(true && document.createElement("div").classList.add) will not work as add is getting evaluated with && expression and after this its returning context of the expression (true && document.createElement("div").classList.add) which is add() { [native code] } and not classList and here we are trying to call add on add function.

When you are trying pass class name ("c") to add then this is not classlist any more hence Illegal invocation

Anil
  • 3,722
  • 2
  • 24
  • 49
-7

What you are tryng to do doesnt make sense. Maybe you mean

var added document.createElement("div").classList.add("c")
If (added){...….}

In your example you have a ) too much after add

Gillis Haasnoot
  • 2,229
  • 1
  • 19
  • 23