2009-11-30 6 views
20

Dans les réponses à this question, nous lisons que function f() {} définit le nom localement, tandis que [var] f = function() {} le définit globalement. Cela me semble logique, mais il y a un comportement étrange qui est différent entre les deux déclarations.JavaScript: Comment "function onload() {}" est-il différent de "onload = function() {}"?

J'ai fait une page HTML avec le script

onload = function() { 
    alert("hello"); 
} 

et cela a fonctionné comme prévu. Quand je l'ai changé à

function onload() { 
    alert("hello"); 
} 

rien ne s'est passé. (Firefox a quand même déclenché l'événement, mais pas WebKit, Opera et Internet Explorer, bien que franchement je n'ai aucune idée de ce qui est correct.)

Dans les deux cas (dans tous les navigateurs), j'ai pu vérifier que les deux window.onload et onload ont été mis à la fonction. Dans les deux cas, l'objet global this est défini sur la fenêtre, et peu importe comment j'écris la déclaration, l'objet window reçoit la propriété très bien.

Que se passe-t-il ici? Pourquoi une déclaration fonctionne-t-elle différemment de l'autre? Est-ce une bizarrerie du langage JavaScript, du DOM ou de l'interaction entre les deux?

+1

Je commence à soupçonner que c'est un bug dans Webkit/Opera et que Firefox a le bon comportement. – Wogan

+0

Ni l'un ni l'autre n'est correct en soi. L'objet global (auquel se réfère 'window') peut avoir des propriétés définies par l'hôte (telles que' onload') et une implémentation ECMAScript 3 est libre d'implémenter le comportement d'une telle propriété comme il le souhaite, y compris l'interne '[[Put ]] 'méthode appelée lorsque la valeur de la propriété est affectée. –

+0

Dans Firefox 3.5.5, je vois l'alerte si j'utilise 'onload = function() {...};' mais pas avec 'var onload = function() {...};' –

Répondre

4

Ces deux fragments déclarent une fonction dans la portée actuelle, appelée "onload". Aucune liaison n'est faite.

function onload() { ... } 

.

var onload = function() { ... } 

Cet extrait attribue une fonction à une propriété/variable/champ « onload » sur la portée actuelle:

onload = function() { ... } 

La raison pour laquelle Firefox effectué la liaison et a déclenché l'événement onload le 1er snippet et les autres ne le sont peut-être pas parce que le chrome chrome (son interface utilisateur) est lui-même écrit et automatisé en utilisant JavaScript - c'est pourquoi il est si flexible et facile d'écrire des extensions dessus. D'une certaine manière, lorsque vous avez déclaré la fonction onload de portée locale de cette façon, Firefox a "remplacé" l'implémentation window (le plus probable du contexte local à l'époque) de onload (à ce moment, une fonction vide ou indéfinie), lorsque l'autre navigateurs correctement "bac à sable" la déclaration dans une autre portée (par exemple, global ou quelque chose).

+0

Bonne observation que Firefox est écrit * en * JavaScript. –

+1

Eh bien, pas complètement, mais la plupart de son chrome (interface utilisateur) est. –

0
var onload = function() { 
    alert("hello"); 
} 

Le déclarera aussi localement.

Je vous suggère de lire cet article très utile: http://kangax.github.io/nfe/

+2

C'est un bon article, mais il ne répond pas à la question. –

4

Beaucoup de gens pointent correctement la différence globale/locale entre (MISE À JOUR: Ces réponses ont pour la plupart été retirés par leurs auteurs maintenant)

var x = function() { 

et

function x() { 

Mais cela ne répond pas réellement votre question spécifique car vous ne faites pas réellement le premier de ceux-ci.

La différence entre les deux dans votre exemple est la suivante:

// Adds a function to the onload event 
onload = function() { 
    alert("hello"); 
} 

Alors que

// Declares a new function called "onload" 
function onload() { 
    alert("hello"); 
} 
+0

Peut-être que c'est parce que ce dernier est évalué au moment de l'analyse, donc l'objet 'window' n'est pas encore prêt à accepter les événements? –

+0

La déclaration d'une fonction appelée "onload" ne le lie pas explicitement à l'événement onload - vous devrez donc toujours dire aux navigateurs d'appeler la fonction "onload" lorsque l'événement "onload" se déclenchera (bien que certains puissent le supposer) . – Fenton

+0

Vraiment? Assigner une fonction à 'window.onload' fonctionne bien dans mon expérience. –

1

Voici ce que je pense est en cours, sur la base de Tim Bas commentaires et une brève discussion avec Jonathan Penn :

Lorsque l'interpréteur JavaScript affecte à la propriété window.onload, il parle à un objet que le navigateur lui a donné. Le setter qu'il appelle remarque que la propriété est appelée onload, et ainsi va au reste du navigateur et câbler l'événement approprié. Tout cela est en dehors de la portée de JavaScript - le script voit juste que la propriété a été définie.

Lorsque vous écrivez une déclaration function onload() {}, le setter n'est pas appelé de la même manière.Puisque la déclaration provoque une affectation à parse temps, pas l'heure d'évaluation, l'interpréteur de script va de l'avant et crée la variable sans le dire au navigateur; ou bien l'objet fenêtre n'est pas prêt à recevoir des événements. Quoi qu'il en soit, le navigateur n'a pas l'occasion de voir l'assignation comme il le fait lorsque vous écrivez onload = function() {}, qui passe par la routine normale setter.

-1

Cela génère une erreur:

foo(); 
var foo = function(){}; 

Cela ne signifie pas:

foo(); 
function foo(){} 

La seconde syntaxe est donc plus agréable lorsque vous utilisez les fonctions modularisation et organiser votre code, alors que le premier La syntaxe est plus agréable pour le paradigme fonctionnal-data.

+0

Ceci est une réponse à [var functionName = function() {} par rapport à function functionName() {}] (http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname); il ne répond pas à * cette * question, qui concerne les liaisons d'événements sur 'window'. – apsillers

0

L'explication la plus simple:

function aaaaaaa(){ 

Peut être utilisé avant qu'il ne soit declarated:

aaaaaaa(); 
function aaaaaaa(){ 

} 

Mais cela ne fonctionne pas:

aaaaaaa(); 
aaaaaaa=function(){ 

} 

C'est parce que dans le troisième code , vous affectez aaaaaaa à une fonction anonyme, sans la déclarer en tant que fonction.