3.7.06

Parenthesis "scope" in FX

It turns out that wrapping an object in parenthesis not only allows you to manipulate it. Quite literally, the parenthesis provides a wrapper so one can access properties and methods of an object, sometimes in a non-intuitive way:

Number.between = function () {...};
(3).between(2, 5);


A more common application is the use of anonymous functions to provide a scope for variables. This method allows a developer to keep memory clean, by effectively providing an encapsulating block:

(function(){
var x = 12;
alert(x);
})();


Now, straight to the point: Wrapping a function makes it invisible to Firefox, as if the parenthesis themselves provided a "scope". If you try the following code in Firefox and IE, it will fail in Firefox but it will work in IE:

(function testme(){
alert('success!');
})();

testme();
// this will break in Firefox

In my uneducated opinion, the parenthesis should only provide a wrapper --a "handle", perhaps-- so that the function can be called immediately after being declared. Since the function was given a name, this name should be available in global scope, but we see this is not the case for Firefox.

Update: As a more versed reader points below, this is due to a different ECMAScript implementation. FX has it right, IE has it wrong. I have to say it's more handy the way IE did it.

2 comments:

Daniel James said...

Sorry about a late comment, I just stumbled upon this. Firefox is correct according to ECMAscript. It defines two types of functions - function declarations and function expressions.

Function declarations must have a name - which is added to their surrounding scope.

Function expressions can optionally have a name, but this is not added to their surrounding scope. It is available inside the function - so it can make recursive calls, or store variables in the function object, eg.

function foo(f) {
alert(f()); // 1
alert(f.x); // 2
}

foo(function bar() {
bar.x = 2;
return 1;
});

The interpreter decides which type of function is declared by its context - if the keyword function is the first token of a statement it's a function declaration, otherwise it's a function expression. This is why the brackets indicate that the function is an expression. Another way to write your example:

+function testme(){
alert('success!');
}();

testme(); // this will break in Firefox

Here, the unary plus prevents the function from being a declaration.

But, as you've observed, different browsers implement this differently. Safari and Konqueror often refuse to parse named function expressions, or just ignore the name altogether. Which makes named function expressions unusable - a pity as they can be useful.

brito said...

@Daniel: Thx for the comment! Late comments are much better than no comments.

There are two situations where I have used named function expressions.

1. When including a script that modifies the BODY element, which can make IE crash:

(function foo(){
if(!document.readyState ||
document.readyState == 'complete'){
document.body.appendChild(someNode);
} else { setTimeout(foo, ); })();

There's clearly much better ways to achieve this, so I'll move on to the second example

2.When declaring methods for a constructor, so I can see the stack in the debugger:

function Foo(){
this.bar = function bar(){};
}

When I see the stack in MSDE, instead of a bunch of anonymous functions, I'll see "bar".