Быстрое исправление - Добавить точку с запятой
Добавьте точку с запятой в конце определения функции:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; // <======
[1,2,3].demo();
И это будет работать.
Что происходит?
Проблема в том, что [1,2,3]
комбинируется с предыдущей функцией (пробелы между ними свернуты). В этом случае [1,2,3]
становится просто [3]
и пытается прочитать свойство [3]
из функционального объекта. Если поставить точку с запятой в конце определения функции, то это означает конец оператора определения функции, и [1,2,3]
можно интерпретировать как определение статического массива.
Все дело в контексте. В некоторых случаях в Javascript [x]
является доступом к свойству. В других случаях это определение статического массива. Без точки с запятой она интерпретировалась как доступ к свойству вместо определения массива.
Помните, что функции - это объекты в Javascript, поэтому они могут иметь свойства и могут отвечать на [x]
как доступ к свойствуих.
Таким образом, без точки с запятой в конце функции у вас, по сути, есть это:
Array.prototype.demo = function() {...}[3].demo();
Поскольку пробел между конечной функцией и * 1034 свернут*. Это означает, что интерпретатор JS ожидает, что []
будет именем свойства, поэтому он оценивает инструкцию внутри []
и в этом контексте [1,2,3]
превращается в [3]
(1,2,3
оценивается, что принимает значениепоследнее разделенное запятыми утверждение, которое 3
).
Более подробное объяснение
Думайте об этом так:
// 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();
Функции являются объектами
В качестве демонстрации того, как функции являются объектами, посмотрите этот пример, который действительно работает!
// 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();
Здесь мы фактически помещаем свойство в свойство [3]
функции, поэтому, когда f[1,2,3]
читает это свойство, оно фактически получает объект с .demo()
метод, так что когда мы потом вызываем, все работает. Я не предполагаю, что кто-то когда-либо будет так кодировать, но я пытаюсь проиллюстрировать, как f[1,2,3]
просто читает свойство [3]
из функционального объекта.
Хорошая причина, чтобы не пропускатьточки с запятой
Эти странные случаи являются хорошей причиной, чтобы не пропускать точки с запятой, даже если вам (но не всегда) это сходит с рук.