Quick Fix - Add Semi-colon
Add a semi-colon at the end of your function definition:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; // <======
[1,2,3].demo();
And, it will work.
What's Happening?
The problem is that the [1,2,3] is being combined with the previous function (whitespace between them collapsed). In that circumstance, the [1,2,3] becomes just [3] and tries to read the [3] property from the function object. If you put the semi-colon at the end of the function definition, then that signals the end of the function definition statement and the [1,2,3] can then be interpreted as a static array definition.
It's all about context. In some circumstances in Javascript, [x] is a property access. In other circumstances, it's a static array definition. Without the semi-colon, it was getting interpreted as the property access instead of the array definition.
Remember that functions are objects in Javascript so they can have properties and can respond to [x] as a property access on them.
So, without the semi-colon at the end of the function you essentially have this:
Array.prototype.demo = function() {...}[3].demo();
Because the whitespace is collapsed between the end of your function and the [1,2,3]. That means the JS interpreter is expecting the [] to be a property name so it evaluates the statement inside the [] and in that context [1,2,3] turns into [3] (the 1,2,3 is evaluated which takes the value of the last comma separated statement which is 3).
More Detailed Explanation
Think of it like this:
// defines function
let f = function() {};
// attempts to read a property from that function object
let o = f [1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Functions Are Objects
As a demonstration of how functions are objects, see this example that actually works!
// defines function
let f = function() {};
f[3] = {demo: function() { console.log("demo!!!");}}
// attempts to read a property from that function object
let o = f[1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Here, we actually put a property on the [3] property of the function so when f[1,2,3] reads that property, it actually gets an object with a .demo() method on it so when we then call it, it all works. I'm not suggesting one would ever code this way, but I am trying to illustrate how f[1,2,3] is just reading the [3] property from the function object.
Good Reason Not to Leave out the Semi-colons
These odd cases are a good reason not to leave out semi-colons, even though you usually (but not always) get away with it.