Вызов пользовательского метода для прототипа Array в Nodejs - PullRequest
0 голосов
/ 21 ноября 2019

Я пытаюсь добавить пользовательский метод в прототип объекта Array:

Array.prototype.demo = function(){
    this.forEach(i=>console.log(i))
}

Но я получаю сообщение об ошибке ниже, когда вызываю метод следующим образом:

[1,2,3].demo()

// Error: TypeError: Cannot read property 'demo' of undefined

Тем не менее, он успешно работает, когда я изменяю его на:

const arr = [1,2,3];
arr.demo()

// Output: 1, 2, 3

PS. Это в nodejs Чтобы воспроизвести ошибку в браузере, скопируйте / вставьте полный блок сразу и нажмите Enter.

ОБНОВЛЕНИЕ: Похоже, нам нужно добавить точку с запятой, чтобы она работала:

Array.prototype.demo = function(){
    this.forEach(i=>console.log(i))
};   <=== added semicolon here to work @jfriend00

[1,2,3].demo();

Однако, теперь этот следующий код работает без точки с запятой !!

String.prototype.demo = function(){
    this.split('').forEach(c=>console.log(c))
}

'hello'.demo();

Ответы [ 2 ]

2 голосов
/ 21 ноября 2019

Быстрое исправление - Добавить точку с запятой

Добавьте точку с запятой в конце определения функции:

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] из функционального объекта.

Хорошая причина, чтобы не пропускатьточки с запятой

Эти странные случаи являются хорошей причиной, чтобы не пропускать точки с запятой, даже если вам (но не всегда) это сходит с рук.

1 голос
/ 21 ноября 2019

Причина в том, что функции являются объектами, поэтому, если мы не добавим точку с запятой, JavaScript попытается получить доступ к свойству объекта функции, после того как он вычислит оператор запятой следующим образом:

function() { ... }[1,2,3].demo();
function() { ... }[3].demo();
undefined.demo();
...