Вопрос об ассоциативности Javascript «Uncaught TypeError: объект не является функцией»

95

Код выглядит следующим образом:

<body>
    <a href="javascript:;" id="test">hello</a>
</body>

<script type="text/javascript">
    document.getElementById("test").addEventListener("click", function () {
      test()
    }, false)
    function test() {
      var postTypes = new Array('hello', 'there')   
      (function() { alert('hello there') })()
    }
</script>

Это вызовет:

«Uncaught TypeError: объект не является функцией»

Если я заключу вызов / вызов анонимной функции в другой набор круглых скобок, он выполнит предупреждение, но все равно выдаст мне ошибку. Если я поставлю точку с запятой после определения var postTypes, все будет в порядке.

Меня заставили поверить, что javascript не требует точки с запятой, поэтому я предполагаю, что существуют некоторые странные правила ассоциативности приложения функций, которые я не полностью понимаю. Почему я получаю эту ошибку?

ПольшаВесна
источник
Похоже, вы пытаетесь создать как анонимную, так и статическую функцию и ожидаете, что она будет выполняться как одна. Что произойдет, если вы удалите function ()
brumScouse

Ответы:

88

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

К сожалению, код

var a = new B(args)(stuff)()

не делает , не приводит к синтаксической ошибке, так что не ;будет вставлено. (Пример, который можно запустить,

var answer = new Function("x", "return x")(function(){return 42;})();

Чтобы избежать подобных сюрпризов, приучите себя всегда заканчивать утверждение словами ;.


* Это всего лишь практическое правило и не всегда верно. Правило вставки намного сложнее. Эта страница блога о вставке точки с запятой содержит более подробную информацию.

Kennytm
источник
13
Или: Чтобы избежать подобных сюрпризов, приучите себя писать чистый читаемый код (который всегда должен применяться) и знать общие правила ASI ... на самом деле это ничем не отличается от «знания» того, как работают замыкания в JS.
18

В вашем коде возникает ситуация, когда процесс автоматической вставки точки с запятой (ASI) не выполняется.

Никогда не следует полагаться на ASI. Вы должны использовать точки с запятой для правильного разделения операторов:

var postTypes = new Array('hello', 'there'); // <--- Place a semicolon here!!

(function() { alert('hello there') })();

Ваш код действительно пытался вызвать объект массива.

Кристиан К. Сальвадо
источник
Один из способов решить проблему, но я не могу обойти Крокфорд-клуб.
1
@pst: Позвольте мне перефразировать, я не в Crock's-клубе вообще :)
Christian C. Salvado
В таком случае прошу прощения за резкие слова :(
Мне понравилась викторина. ASI действительно ужасно сбивает с толку неприглядным кодом!
8

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

Наоми
источник
То же самое здесь, у меня была переменная с именем, alertи я пытался вызвать функцию предупреждения javascript, и она говорила, что предупреждение не является функцией. Он пытался вызвать alertпеременную вместо фактической функции
James111
0

Постарайтесь разместить тело функции перед вызовом функции в вашем файле JavaScript.

CMPE
источник
0

Я получал ту же ошибку и полтора дня пытался найти решение. Ответ Наоми привел меня к нужному мне решению.

Мой ввод (type = button) имел атрибут name, идентичный имени функции, которая вызывалась событием onClick. Как только я изменил атрибут, nameвсе заработало.

<input type="button" name="clearEmployer" onClick="clearEmployer();">

изменился на:

<input type="button" name="clearEmployerBtn" onClick="clearEmployer();">
tbriggs707
источник
0

У меня эта ошибка возникает при компиляции и связывании TS с WebPack. Он компилируется export class AppRouterElement extends connect(store, LitElement){....}в let Sr = class extends (Object(wr.connect) (fn, vr)) {....}который кажется неправильным из - за отсутствия запятой. При объединении с Rollup ошибок нет.

Дзинтарс
источник