21

In the answers to this question, we read that function f() {} defines the name locally, while [var] f = function() {} defines it globally. That makes perfect sense to me, but there's some strange behavior that's different between the two declarations.

I made an HTML page with the script

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

and it worked as expected. When I changed it to

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

nothing happened. (Firefox still fired the event, but WebKit, Opera, and Internet Explorer didn't, although frankly I've no idea which is correct.)

In both cases (in all browsers), I could verify that both window.onload and onload were set to the function. In both cases, the global object this is set to the window, and I no matter how I write the declaration, the window object is receiving the property just fine.

What's going on here? Why does one declaration work differently from the other? Is this a quirk of the JavaScript language, the DOM, or the interaction between the two?

7
  • 1
    I'm beginning to suspect this is a bug in Webkit/Opera and that Firefox has the correct behaviour. Commented Nov 30, 2009 at 9:27
  • Neither is correct per se. The global object (to which window refers) may have host defined properties (such as onload) and an ECMAScript 3 implementation is free to implement the behaviour of such a property as it sees fit, including the internal [[Put]] method that is called when the value of the property is assigned. Commented Nov 30, 2009 at 9:58
  • In Firefox 3.5.5, I see the alert if I use onload = function() {...}; but not with var onload = function() {...}; Commented Nov 30, 2009 at 10:09
  • 2
    I'm not sure about a miracle, but based on the observed inconsistencies I'd certainly recommend against using the var onload = ... and function onload() {...} forms. window.onload = function() {...}; is not part of any current standard but pretty universally much supported across browsers, as is <body onload="...">. A combination of window.addEventListener and window.attachEvent will allow you to add multiple event handlers in all the major browsers, but beware of differences between the two. Commented Nov 30, 2009 at 10:32
  • 2
    This is unrelated to your problem, but you might be interested to know why it's a good idea to avoid onload = function(){...} pattern — thinkweb2.com/projects/prototype/… Commented Dec 11, 2009 at 15:44

6 Answers 6

4

This two snippets declares a function in the current scope, named "onload". No binding is done.

function onload() { ... }

.

var onload = function() { ... }

This snippet assigns a function to a property/variable/field named "onload" on the current scope:

onload = function() { ... }

The reason why Firefox performed the binding and raised the onload event on the 1st snippet and the others didn't might be because the Firefox chrome (its user interface) itself is written and automated using JavaScript - that's why it's so flexible and easy to write extensions on it. Somehow, when you declared the locally-scoped onload function that way, Firefox "replaced" the window's (most likely the local context at the time) implementation of onload (at that time, an empty function or undefined), when the other browsers correctly "sandboxed" the declaration into another scope (say, global or something).

Sign up to request clarification or add additional context in comments.

2 Comments

Good observation that Firefox is written in JavaScript.
Well, not completely, but most of his chrome (user interface) is.
4

Many people are correctly pointing out the global / local difference between (UPDATE: Those answers have mostly been removed by their authors now)

var x = function() {

and

function x() {

But that doesn't actually answer your specific question as you aren't actually doing the first one of these.

The difference between the two in your example is:

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

Whereas

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

4 Comments

Maybe it's because the latter gets evaluated at parse time, so the window object isn't quite ready to accept events yet?
Really? Assigning a function to window.onload works well in my experience.
According to the ECMAScript 3 spec, var x = function() {...}; and function x() {...} should set properties of the same variable object, which in the case of global code is the global object, which is more or less equivalent to window in most browsers, so your answer doesn't really answer the question.
@Sohnee: my point was that there is no "global / local difference" between var x = function() {...}; and function x() {...} declared in the same scope.
1

Here's what I think is going on, based on Tim Down's helpful comments and a brief discussion with Jonathan Penn:

When the JavaScript interpreter assigns to the window.onload property, it's talking to an object that the browser has given it. The setter that it invokes notices that the property is called onload, and so goes off to the rest of the browser and wires up the appropriate event. All of this is outside the scope of JavaScript — the script just sees that the property has been set.

When you write a declaration function onload() {}, the setter doesn't get called in quite the same way. Since the declaration causes an assignment to happen at parse time, not evaluation time, the script interpreter goes ahead and creates the variable without telling the browser; or else the window object isn't ready to receive events. Whatever it is, the browser doesn't get a chance to see the assignment like it does when you write onload = function() {}, which goes through the normal setter routine.

Comments

0

The simplest explanation:

function aaaaaaa(){

Can be used before it is declarated:

aaaaaaa();
function aaaaaaa(){

}

But this doesn't work:

aaaaaaa();
aaaaaaa=function(){

}

That's because in the third code, you are assigning aaaaaaa to an anonymous function, not declaring it as a function.

Comments

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

Will declare it locally too.

I suggest you to read this very helpful article : http://kangax.github.io/nfe/

1 Comment

That's a great article, but it doesn't answer the question.
-1

This generates an error:

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

This doesn't:

foo();
function foo(){}

The second syntax is therefore nicer when you're using functions to modularize and organize your code, whereas the first syntax is nicer for the functions-as-data paradigm.

1 Comment

This is an answer to var functionName = function() {} vs function functionName() {}; it does not answer this question, which is about event bindings on window.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.