1

Why does

function Example() {
  this.go();
}
Example.prototype.go = function() {
    console.log("going");
  }
  (new Example());

bark at me that this.go is not a function whereas

function Example() {
  this.go();
}
Example.prototype.go = function() {
  console.log("going");
}
new Example();

is logging correctly as expected?

Execution environment is node v10.4.1 on macOS High Sierra 10.13.4

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205

3 Answers3

3

You are depending on ASI and it isn't working the way you expect.

In the first example, the () are turning the function expression you are trying to assign to Example.prototype.go into an IIFE.

Consequently, the order of events is:

  1. Example is defined
  2. new Example() is evaluated
  3. The result is passed as an argument in a call to the anonymous function
  4. The return value of that function (undefined) is assigned to Example.prototype.go

… except it errors at step 2 because go isn't defined at that point.

End each statement with an explicit semi-colon to avoid this.

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
2

It's because you're relying on Automatic Semicolon Insertion (ASI) (perhaps unintentionally), but also starting a line with a (. If you correctly terminate the assignment with a ;, the problem goes away:

function Example() {
  this.go();
}
Example.prototype.go = function() {
    console.log("going");
}; // <==== ; here
(new Example());

The problem is that without the ;, the () expression following the assignment combines with the function() { } expression in front of it in a syntactically- (but not logically-) valid way: It calls the function, passing in the result of new Example. So ASI doesn't kick in.

If you aren't intentionally relying on ASI, just note that assignment expressions need to be terminated with ;s.

If you are intentionally relying on ASI, you must start lines that have a leading ( or [ with a proactive ; for this very reason. So in your case:

    function Example() {
      this.go();
    }
    Example.prototype.go = function() {
        console.log("going");
    }
    ;(new Example());
//  ^----
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
1

The problem is that you forgot a semicolon after the function expression assigned to .go:

Example.prototype.go = function() {
  console.log("going");
} // <--- no semicolon!
(new Example());

The following line beings with opening parentheses - thus, the interpreter thinks you're immediately calling the aforementioned function:

Example.prototype.go = function() {
  console.log("going");
}(new Example());

This is happening before Example.prototype.go has been assigned to - the interpreter is trying to evaluate the right-hand side of the expression to a value before assigning the result to Example.prototype.go. But you're calling new Example() before Example.prototype.go is populated; thus, this.go is undefined.

Just put a semicolon after the } instead:

Example.prototype.go = function() {
  console.log("going");
};
(new Example());
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209