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:

  1. Anonymous12:32 PM

    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.

    ReplyDelete
  2. @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".

    ReplyDelete