24.01.11

New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited

Function statements in ECMAScript

What’s the effect of this program according to ECMAScript?

function foo() { }

If you said that it defines a function as a property of the global object, congratulations! You’ve mastered a basic part of JavaScript syntax.

Let’s go a little trickier: what is the effect of the function defined in this program according to ECMAScript?

function foo()
{
  return g;
  function g() { }
}

This function, when called, defines a local variable g whose value is the specified function. Then it returns that function as the value of that variable. If you knew this as well, give yourself a gold star.

Now let’s try something even harder: what’s the effect of these programs?

if (true)
  function bar() { }
function g() { }
function foo()
{
  if (true)
    function g() { }
  return g;
}

Shenanigans!

Trick question! They fail to run due to syntax errors.

ECMAScript permits function statements in exactly two places: directly within the list of statements that make up a program, and directly within the list of statements that make up the contents of a function body. These are the first two examples. (A function statement also looks like an expression, but if it appears in expression context it’s a function expression, not a function statement.) Engines which permit a function statement anywhere else — as the child of a block statement enclosed by curly braces, as the child of a loop or condition, as the child of a with, or as the child of a case or default in a switch statement — do so by extending ES5.

Spec requirements aside, what are the semantics of extensionland function statements?

Now you’re just messing with me

Which semantics?

Browsers all implement extensionland function statements differently, with different semantics. Use them just so and they’ll work the same way across browsers. Use them in any way where the function statement conditionally executes, or where you start capturing the binding for the function in different locations, and you’ll find any semblance of cross-browser compatibility disappears. This example by Rich Dougherty, used with permission, demonstrates some of the incompatibilities (and I wonder whether function statements in with might present more):

var result = [];
result.push(f());
function f() { return 1; }
result.push(f());
if (1)
{
  result.push(f());
  function f() { return 2; }
  result.push(f());
}
result.push(f());
function y()
{
  result.push(g());
  function g() { return 3; }
  result.push(g());
  if (1)
  {
    result.push(g());
    function g() { return 4; }
    result.push(g());
  }
  result.push(g());
}
y();
print(result);

Results in different browsers vary a fair bit, although there’s a little more consensus on behavior now than at the time this example was originally written:

Browser Output
Firefox 1.5 and 2 1,1,1,2,2,3,3,3,3,3
Firefox 4 1,1,1,2,2,3,3,3,4,4
Opera 2,2,2,2,2,4,4,4,4,4
Internet Explorer 7 2,2,2,2,2,4,4,4,4,4
Safari 3 1,1,2,2,2,3,3,4,4,4
Safari 4 2,2,2,2,2,4,4,4,4,4
Chrome 2,2,2,2,2,4,4,4,4,4

Why not specify semantics?

Blindly specifying some particular behavior won’t work. Many sites these days (and different browser-specific implementations of those sites) rely on engine-specific behavior with user-agent-conditioned code. Changing browser behavior breaks that pretty hard. Specification will break any browsers not already implementing it at time of specification.

A way forward

The next version of ECMAScript would like to specify semantics for this case — quite possibly semantics not implemented by any browser. How to do it, if implementations irreconcilably disagree? The solution comes in two parts. First, “ES6” will require affirmative opt-in to enable new syntax and semantics, including for currently-nonstandard function statements. Second, in anticipation of that change, the ECMA committee recommends that non-standard function statements be forbidden in strict mode code, to open up a future path down which ES6 can walk.

To permit ES6 to standardize semantics, the ECMA committee recommends forbidding non-standard function statements in strict mode code. Thus these examples are syntax errors:

"use strict";
{
  function foo() { }
}
"use strict";
if (true)
  function bar() { }
"use strict";
with (obj)
  function foo() { }
"use strict";
for (;;)
  function foo() { }
"use strict";
switch (v)
{
  case 10:
    function bar() { }
  default:
    function baz() { }
}

Both Firefox and WebKit now implement this restriction, and other engines will follow as they too implement strict mode.

Conclusion

In order for future versions of ECMAScript to be able to define semantics for extensionland functions, strict mode “clears the deck” and forbids them entirely. Instead, assign functions to variables, a la var f = function() { };. Semantics for this are completely defined and compatibly implemented across browsers.

You can experiment with a version of Firefox with these changes by downloading a nightly build. (Don’t forget to use the profile manager if you want to keep the settings you use with your primary Firefox installation pristine.)

6 Comments »

  1. [...] This post was mentioned on Twitter by Planet Mozilla, jsgoodies. jsgoodies said: Function syntax; explains when functions can and cannot be declared: http://js.gd/1bj [...]

    Pingback by Tweets that mention Where's Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited -- Topsy.com — 25.01.11 @ 07:22

  2. [...] strict mode prohibits function statements not at the top level of a script or function. In normal code in browsers, function statements are permitted “everywhere”. This is [...]

    Pingback by ECMAScript 5 strict mode in Firefox 4 ✩ Mozilla Hacks – the Web developer blog — 25.01.11 @ 11:24

  3. [...] drugie, tryb ścisły nie pozwala na deklarowanie funkcji poza najwyższym poziomem skryptu i funkcji. W zwykłym trybie w przeglądarkach deklaracje funkcji są dozwolone wszędzie. Nie jest to [...]

    Pingback by Mozilla Hacks: ECMAScript 5 Strict Mode – tryb ścisły w ECMAScripcie 5 « marcoos.techblog — 25.01.11 @ 14:28

  4. [...] Para más información al respecto, puede visitiarse: New ES5 strict mode requirement: function statements not at top level of a program or function are p… [...]

    Pingback by Strict Mode en Javascript( ECMAScript 5 ) | EtnasSoft — 01.03.11 @ 04:18

  5. [...] Para más información al respecto, puede visitiarse: New ES5 strict mode requirement: function statements not at top level of a program or function are p… [...]

    Pingback by Strict Mode en Javascript ( ECMAScript 5 ) | EtnasSoft — 22.04.11 @ 05:30

  6. [...] 另外,严格模式禁止在一段脚本或一个方法内有不标准的方法声明。在非严格模式下,浏览器允许在任何地方声明方法。这种方式并不是来自ES5,甚至不是来自ES3!,它是不同浏览器不同的实现导致的。未来的ECMAScript版本将会为不标准的方法声明定义新的语意。严格模式下禁止了这种方法申明,为未来的ECMAScript标准的定制扫清障碍。 [...]

    Pingback by [转载]JavaScript严格模式 – WEB前端开发- 专注前端开发,关注用户体验 — 15.06.13 @ 05:25

RSS feed for comments on this post. TrackBack URI

Leave a comment

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>