7

I am new to Javascript language, recently I started looking into js prototype and got confused by some odd output in below code:

Array.prototype.print = function() {
  console.log(this)
}

[1, 2, 3, 4].print();

Could anyone tell me why it returns

Cannot read property 'print' of undefined'

If I declare var array = [1, 2, 3, 4] then call print function by array.print(), it works fine, so I got confused how is that different?

Array.prototype.print = function() {
  console.log(this)
}

var array = [1, 2, 3, 4]
array.print()
CRice
  • 29,968
  • 4
  • 57
  • 70
chen.w
  • 129
  • 1
  • 7
  • Are you running both blocks of code at the same time? It works for me when I run each block separately, which suggests a race condition. Make sure the first function has run before final line is called. – Jamie Weston Aug 08 '18 at 17:50

2 Answers2

6

You could just add a semicolon to separate an access to the function.

What you have is a property accessor to the function expression with comma operators which return 4 for the access. The ASI (automatic semicolon insertion) does not work in this case.

Array.prototype.print = function() {
  console.log(this)
}[1, 2, 3, 4] //.print();   // tries to get property 4 of the function
                            // and then tries to call a function from undefined

It needs a semicolon after the block statement of the function expression.

Array.prototype.print = function() {
  console.log(this)
};

[1, 2, 3, 4].print();
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

If you run the whole code block in one go, there is no guarantee that the last line will run after the first block.

Running the two blocks separately will highlight this difference, and you will see the correct output from the second block.

Run this first:

Array.prototype.print = function() {
  console.log(this)
}

Then run this:

[1, 2, 3, 4].print();

There are several approaches you can take to getting them to run asynchronously. An easy one would be to wrap the last line in a setTimeout (this may not be appropriate depending on your usage).

E.g.

Array.prototype.print = function() {
  console.log(this)
}

setTimeout(()=> { 
    [1, 2, 3, 4].print();
}, 1000)
Calvin Nunes
  • 6,376
  • 4
  • 20
  • 48
Jamie Weston
  • 351
  • 4
  • 14
  • Thanks for your solution which is absolutely right, it is kinds weird that js forces this two statements into one and run them at the same time – chen.w Aug 08 '18 at 18:04