Javascript Question d'associativité «Uncaught TypeError: object is not a function»

93

Le code est le suivant:

<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>

Cela lancera un:

"Uncaught TypeError: l'objet n'est pas une fonction"

Si j'emballe l'appel / l'invocation de fonction anonyme dans un autre ensemble de parenthèses, il exécutera l'alerte, mais me donnera toujours une erreur. Si je mets un point-virgule après la définition de "var postTypes", cela ira parfaitement.

J'ai été amené à croire que javascript ne nécessite pas de points-virgules, donc je suppose qu'il existe des règles d'associativité étranges d'application de fonction que je ne comprends pas entièrement. Pourquoi ai-je cette erreur?

PolognePrintemps
la source
On dirait que vous essayez de créer à la fois une fonction anonyme et une fonction statique et vous attendez à ce qu'elle s'exécute en une seule. Que se passe-t-il si vous supprimez function ()
brumScouse

Réponses:

86

JavaScript nécessite des points-virgules, c'est juste que l'interpréteur les insérera pour vous sur les sauts de ligne si possible * .

Malheureusement, le code

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

n'entraîne pas d' erreur de syntaxe, donc no ;sera inséré. (Un exemple qui peut fonctionner est

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

Pour éviter de telles surprises, entraînez-vous à toujours terminer une déclaration avec ;.


* Ceci est juste une règle de base et pas toujours vrai. La règle d'insertion est beaucoup plus compliquée. Cette page de blog sur l'insertion de points-virgules contient plus de détails.

KennyTM
la source
13
Ou: Pour éviter de telles surprises, entraînez-vous à écrire du code lisible propre (qui devrait toujours s'appliquer) et à connaître les règles générales ASI ... ce n'est vraiment pas différent de "savoir" comment fonctionnent les fermetures dans JS.
18

Votre code rencontre un cas où le processus d' insertion automatique de point-virgule (ASI) ne se produit pas.

Vous ne devriez jamais compter sur ASI. Vous devez utiliser des points-virgules pour séparer correctement les instructions:

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

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

Votre code essayait en fait d'appeler l'objet tableau.

Christian C. Salvadó
la source
Une façon de résoudre le problème, mais je ne peux pas me mettre derrière le club de Crockford.
1
@pst: Permettez - moi de reformuler ma question, je ne suis pas dans le Crock's club du tout :)
Christian C. Salvadó
Dans ce cas, je m'excuse pour les mots durs :(
J'ai bien aimé le quiz. ASI est en effet terriblement déroutant avec le code icky!
8

J'ai eu une erreur similaire et il m'a fallu un certain temps pour réaliser que dans mon cas, j'ai nommé la variable tableau payInvoices et la fonction également payInvoices. Cela a confondu AngularJs. Une fois que j'ai changé le nom pour processPayments (), cela a finalement fonctionné. Je voulais juste partager cette erreur et cette solution car il m'a fallu beaucoup de temps pour comprendre cela.

Naomi
la source
Même chose ici, j'avais une variable nommée alertet j'essayais d'appeler la fonction d'alerte javascript et elle disait «l'alerte n'est pas une fonction». Il essayait d'appeler la alertvariable au lieu de la fonction réelle
James111
0

Essayez d'avoir le corps de la fonction avant l'appel de la fonction dans votre fichier JavaScript.

CMPE
la source
0

J'obtenais la même erreur et j'ai passé un jour et demi à essayer de trouver une solution. La réponse de Naomi m'a conduit à la solution dont j'avais besoin.

Mon entrée (type = bouton) avait un attribut nameidentique à un nom de fonction appelé par l'événement onClick. Une fois que j'ai changé l'attribut, nametout a fonctionné.

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

changé en:

<input type="button" name="clearEmployerBtn" onClick="clearEmployer();">
tbriggs707
la source
0

J'ai cette erreur lors de la compilation et du regroupement de TS avec WebPack. Il compile export class AppRouterElement extends connect(store, LitElement){....}dans let Sr = class extends (Object(wr.connect) (fn, vr)) {....}ce qui semble incorrect en raison de la virgule manquante. Lors du regroupement avec Rollup, aucune erreur.

Dzintars
la source