ECMA-262-5 in detail. Chapter 2. Strict Mode.

In this chapter we will concentrate on another innovation of the ECMA-262-5. The topic of the discussion is a strict variant (or strict mode) of an ECMAScript program. We’ll discuss the reasons for providing this feature, how it affects on some already existing semantic aspects and what can it restrict.

Below the general provisions regarding strict variant of the ECMAScript language are described. Let’s start from the reasons for which strictness was made and definition of this mode.

The current version of the specification — ES5 doesn’t change the syntax much. As one of the incompatible syntactic innovations can be mentioned e.g. an accessor property (getter/setter) defined in the declarative view, with using object initialiser. Although, even this new syntactic feature isn’t new for some implementations (e.g. for SpiderMonkey), which had such constructions before standardizing the ES5. Some other new syntax constructions and ideological aspects which can be based on that new syntax are leaved for the future ECMAScript version — ES6 aka Harmony. Instead, all innovations of the ES5 are made in the context of already existed ES3 syntax constructs. From this viewpoint, ES5 and namely all new meta-methods of the Object constructor (such as e.g. Object.create and other) can be treated as just an additional library (a framework) which is being “loaded” before any other library used in a project.

However, without changing the syntax, ES5 provides some important semantic innovations, as e.g. ability to control property attributes, objects extensibility, already mentioned accessor properties, etc. All these features are the good addition for the ES3.

At the same time some features of ES3 were recognized as error-prone, not enough secure or having poor errors checking at parsing stage. In addition, some ES3 features were marked as deprecated and possibly will be removed from the next version of the language. From this point of view, ES5 is a transitional version of the specification.

For that purpose, ECMA-262-5 defines a strict variant of the language. This variant excludes some specific syntactic and semantic features of the regular ECMAScript language and modifies the detailed semantics of some features. The strict variant also specifies additional error conditions that must be reported by throwing error exceptions in some situations that are not specified as errors by the non-strict form.

The strict variant of ECMAScript is commonly referred to as the strict mode of the language.

Strict mode syntax and semantics of ECMAScript is explicitly made at the level of individual ECMAScript code units. That means we can choose whether to process some code unit (e.g. a function) with the strict mode or not.

To define a strict mode we should use a Use Strict Directive of so-called a Directive Prologues.

A Directive Prologues is a sequence of directives represented entirely as string literals which followed by an optional semicolon. A Directive Prologue may be an empty sequence.

More generally (regardless ECMAScript), a Directive Prologues corresponds to a prologue code i.e. some automatically generated code, preprocessing options, or directives.

For example in ECMAScript:

// start of a directive prologue
"first directive";
'the second in the single quotes';
// end of a directive prologue

The meaning of some such directives is special. Currently, ES5 defines only one special directive — already mentioned a Use Strict Directive.

A Use Strict Directive is a directive in a Directive Prologue whose string literal is either the exact character sequences “use strict” or ‘use strict’. A Use Strict Directive may not contain an escape sequence or line continuation. This directive is used for specifying a strict mode of a code unit.

So, to define a strict mode of some code unit we use simply:

"use strict";
// implementation of a module

Notice, that a Directive Prologue may contain more than one Use Strict Directive. However, an implementation may issue a warning if this occurs.

"use strict";
"use strict"; // may be a warning

In addition to the specification, an implementation can use any other directive with specific meaning for the particular implementation. If some directive is not recognized as a special, a warning can be issued. For example, if the implementation reserves additionally “check arguments” directives, then a warning is issued only for the third directive in the following example:

"use strict";
"check arguments";
"use paranoid"; // may be a warning

As we mentioned, we can choose a strictness for a particular code unit, defining a scope of the strict variant. In the following example, we do not use the strict mode for the whole program, but use it only for the foo function:

var eval = 10; // OK

function foo() {
  "use strict";
  alert(eval); // 10
  eval = 20; // SyntaxError
}

foo();

We see the SyntaxError in the second case — that’s because eval identifier is not allowed for assignment in strict mode, although the first assignment, being evaluated in non-strict mode, occurred normally. But all such restrictions we will discuss shortly in detail.

Another thing to note, is that a Directive Prologue is required to be placed exactly at the top of a context code:

// OK, non-strict mode
(function foo() {
  arguments = 10;
  "use strict";
})();

// SyntaxError, strict-mode
(function foo() {
  "use strict";
  arguments = 10;
})();

Besides, the affecting of a strict mode prolongs to all inner contexts. I.e. the context code is a strict code if either its context or any surrounding context contains a Use Strict Directive:

// define strict mode in the global context,
// i.e. for the whole program
"use strict";

(function foo() {
  // strictness is "inherited" from
  // the global context
  eval = 10; // SyntaxError
  (function bar() {
    // the same - from the global context
    arguments = 10; // SyntaxError
  })();
})();

At the same time a strict mode is specified lexically (statically) for a context — just as a closure — where this context is created, but not executed. I.e. the strictness of the context being called is not dependent on the strictness of a caller:

// globally use a non-strict mode

var foo = (function () {
  "use strict";
  return function () {
    alert(this);
  };
})();

function bar() {
  alert(this);
}

// for both functions, a caller is the global context

// but "foo" is evaluated in the strict mode
foo(); // undefined

// meanwhile "bar" is not
bar(); // object

Another important point to notice, that functions created via the Function constructor do not inherit the strictness from the surrounding context. The following example does not throw an exception:

"use strict";

var f = Function("eval", "arguments", " \
  eval = 10; arguments = 20; \
  with ({a: 30}) { \
    alert(a + eval + arguments); \
  }"
);

f(); // OK, 60

But if a strict mode directive is inside such a function, then all restrictions are available:

// non-strict globally

var f = Function("eval", "'use strict'; alert(eval);"); // SyntaxError

Now we are ready to discuss all the cases applied to the strict mode.

Here you can find all restrictions provided by the strict mode of the ECMA-262-5. Some of them, having similar semantics (e.g. “eval” and “arguments” identifiers are not allowed for assignment, function argument names or property names) are combined in one subsection.

At the moment of writing this article (2010-06-01), the only available implementation for testing the strict mode (and the complete implementation of the ES5) — is the BESEN engine written by Benjamin Rosseaux. It of course still has some bugs (some of them I’ve reported while was writing this article and glad to see that several bugs are already fixed), but it is a good candidate for ES5 programming and testing. Implementation is open source, written in Object Pascal. You can download the sources and the IDE from which you can run your tests. Hope, some major implementation will follow soon also.

So, let’s see which restrictions we have in the strict mode of the ES5.

A conforming implementation, when processing strict mode code, may not extend the syntax of numeric literals and escape sequence with octal semantics.

In ES3, if an implementation extended the numeric literal syntax, we had the following case:

// ES3 with octal extension

var x = 010; // octal number
print(x); // 8 - in octal radix

Notice, that even in ES3 octal extension for numeric and string literals was only for backward compatibilities and was defined only in the Annex B (see B.1 Additional Syntax) but not in the main section of numeric or string literals. The same in the ES5 specification — octal extension may be used only for backward compatibilities and only in non-strict mode. It’s also defined in the Annex B of ES5. In strict mode, as we said, octal extension is forbidden:

"use strict";

var x = 010; // always decimal
print(x); // 10 - in decimal radix

The same with escape sequence, e.g. “\0<octal number>”.

This restriction mostly relates to well-known confusion with often used parseInt function, when programmers get “unexpected” result for e.g. “08″ value:

// ES3

parseInt("07"); // 7
parseInt("08"); // 0 ?
parseInt("09"); // 0 ?
parseInt("010"); // 8 ?

That exactly related with the octal extension — 08 isn’t a valid octal number, so it is treated as 0 in parseInt (notice, however, that parseInt had in ES3 its own, independent from numeric literals, handling of octal numbers). To solve the issue a needed radix should be specified in ES3:

parseInt("08", 10); // 8

In ES5, handling of octal case in parseInt algorithm has been removed, so now we can use it without specifying a radix in this case. Notice again, that new parseInt algorithm is applied regardless strict mode and regardless numeric grammar extension:

// ES5, no matter, strict
// or non-strict mode

parseInt("08"); // 8

But, I want to remind, that parseInt is for parsing (that’s why it’s named so) a number from a string. That means, this method does something more than just a type conversion:

parseInt("08Gb", 10); // 8

If you need just a type conversion, an alternative way can be used, e.g. applying the Number constructor as a function — because it exactly performs ToNumber conversion in this case. If the value of an argument is known and can be converted to number, it can be (and could in ES3) safely used without specifying any radix:

Number("08"); // 8

// alternative way
+"08"; // 8

Of course, it won’t parse an argument as parseInt does:

Number("08Gb"); // NaN

As we know, in ES3 assignment to an undeclared identifier creates a new property of the global object (which are often confuse with global variables). This causes also well-known issue related with unintentional polluting of the global scope:

// non-strict mode

(function foo() {
  // local vars
  var x = y = 20;
})();

// unfortunately, "y" wasn't local
// for "foo" function
alert(y); // 20
alert(x); // "x" is not defined

In strict mode this feature has been removed:

"use strict";
a = 10; // ReferenceError

var x = y = 20; // also a ReferenceError

The same situation is with read-only properties, i.e. if a property being either a data property with [[Writable]] attribute set to false or an accessor property without a [[Set]] method. In the following example a TypeError should be thrown:

"use strict";

var foo = Object.defineProperties({}, {
  bar: {
    value: 10,
    writable: false // by default
  },
  baz: {
    get: function () {
      return "baz is read-only";
    }
  }
});

foo.bar = 20; // TypeError
foo.baz = 30; // TypeError

Restricted assignment also relates to augmenting non-extensible objects, i.e. objects having [[Extensible]] property as false:

"use strict";

var foo = {};
foo.bar = 20; // OK

Object.preventExtensions(foo);
foo.baz = 30; // TypeError

In strict mode these names — “eval” and “arguments” are treated as kind of “keywords” (while they are not) and not allowed in several cases.

They cannot appear as a variable declaration or as a function name:

"use strict";

// SyntaxError in both cases
var arguments;
var eval;

// also SyntaxError
function eval() {}
var foo = function arguments() {};

They are not allowed as function argument names:

"use strict";

// SyntaxError
function foo(eval, arguments) {}

It is impossible to assign new values to them (thus, arguments is restricted in the global scope also, but not only in functions):

"use strict";

// SyntaxError
eval = 10;
arguments = 20;

(function (x) {
  alert(arguments[0]); // 30
  arguments = 40; // TypeError
})(30);

They cannot be used with prefix and postfix increment/decrement expressions:

"use strict";

// SyntaxError
++eval;
arguments--;

Regarding objects and their properties, “eval” and “arguments” are allowed in assignment expressions and may be used as property names of objects:

"use strict";

// OK
var foo = {
  eval: 10,
  arguments: 20
};

// OK
foo.eval = 10;
foo.arguments = 20;

However, “eval” and “arguments” are not allowed as parameter names of declarative view of a setter:

"use strict";

// SyntaxError
var foo = {
  set bar (eval, arguments) {
    ...
  }
};

An implementation may not associate special meanings within strict mode functions to properties named caller or arguments of function instances. It is impossible to create or modify properties with these names on function objects in strict mode (caller and callee restrictions will be described in the following section):

"use strict";

function foo() {
  alert(foo.arguments); // SyntaxError
  alert(foo.caller); // SyntaxError
}

foo();

Also, neither “eval”, nor “arguments” cannot be used as an identifier of a catch clause:

"use strict";

try {
  throw Error("...");
} catch (arguments) {} // SyntaxError, the same for "eval" name

Besides restrictions for these names, arguments has additional restriction in semantics. In the strict mode it does not dynamically share its array indexed property values with the corresponding formal parameter bindings of a function. So, array indexed property values of the arguments object are just static copies:

"use strict";

(function foo(x) {

  alert(arguments[0]); // 10
  arguments[0] = 20;

  alert(x); // 10, but not 20

  x = 30;
  alert(arguments[0]); // 20, but not 30

})(10);

Implementation of “eval” also has restriction in semantics in this case — it cannot instantiate a new binding (a variable or function) in the calling context (as it does in non-strict mode). Instead, strict code for eval is executed in its own “sandbox environment”, which is being destroyed after the eval ends:

"use strict";

eval("var x = 10; alert(x);"); // 10
alert(x); // "x" is not defined

Just like “eval” and “arguments” names, “callee” and “caller” identifiers because of some security reasons have been restricted. For example:

// non-strict mode

function foo(x, y) {
  alert(x); // 10
  bar();
  alert(x); // 100
}

function bar() {
  console.dir(bar.caller.arguments); // 10, 20
  bar.caller.arguments[0] = 100;
}

foo(10, 20);

In non-strict mode, arguments.callee still can be used to reference an anonymous function from inside, e.g. for a recursive call. Unfortunately, in strict mode if we want to call a function expression recursively (or just to reference it) we should define a NFE (name function expression):

"use strict";

(function foo(bar) {
  if (!bar) {
    arguments.callee(true); // SyntaxError
    foo(true); // OK
  }
})();

There is one unpleasant consequence related with removing arguments.callee from the strict mode — now it’s not possible to reference a function created via the Function constructor from the inside (e.g. at recursive call) if such function created not in the global context. As we know, the scope chain of Function functions consists only of the global object. Therefore, if such function created inside other function, no any binding name of surrounding function is available for the Function function. We could call such functions in ES3 only via the arguments.callee reference. In ES5 — there is no (at least normal) way to call such function recursively:

(function () {

  // outer name is not available,
  // regardless strictness
  var foo = Function("alert(foo);'");
  foo(); // "foo" is not defined (no such name in the global context)

  // error in strict mode for arguments.callee
  Function("'use strict; alert(arguments.callee);'")(); // TypeError

  // OK in non-strict for arguments.callee
  Function("alert(arguments.callee);'")(); // OK, function

})();

However, if such a strict function is created in the global context, we can use outer variable name to reference it:

var foo = Function("'use strict; alert(foo);'");
foo(); // function

As a variant of solving the issue, a function can be passed as an argument to itself:

(function () {
  var foo = Function("foo", "'use strict'; alert(foo);");
  foo(foo); // OK, function
})();

There can be other tricks for particular cases of the recursive call, e.g. with using constructor property and new operator:

(function () {
  var foo = Function('bool', 'return bool || this.constructor(true);');
  new foo(); // will be called twice
})();

But obviously, such tricks are inconsistent and not for practical usage. The other way of dynamic code creation with using Function constructor can be e.g. this approach, thought we create two functions:

(function () {
  var foo = Function('return function bar() {alert(bar);}')();
})();

Regarding the “caller” property — actually, it was not standardized at all in ES3 — neither as a direct property of a function, nor as a property of the arguments object. However, it is implemented in many current engines. It was marked as obsolete by SpiderMonkey long time ago. So, you may use it at your own risk, although it, being deprecated, is not recommenced.

As a convenient application of the arguments.caller can be mentioned e.g. an implementation of a super concept in a system with the hierarchical inheritance. I.e. a convenient way of calling a parent method (in the prototype chain) with the same name from a child method. For example:

var A = Class({
  foo: function () {
    return "A#foo";
  }
});

var B = Class({
  extends: A,
  foo: function () {
    return this.super() + ", B#foo";
  }
});

// an instance of a "class"
var b = new B();
b.foo(); // "A#foo, B#foo"

//  implementation of Class
// ...
// this.super via "caller" property
super: function () {
  var caller = arguments.caller;
  return caller.class.superproto[caller.name].apply(this, arguments);
}

Thus, an implementation of a Class “meta-constructor” should mark every method with additional class (a direct reference to a “class” instead of using this.constructor — to avoid a recursion on third and deeper inheritance levels when applying this) and name properties (to be able to call appropriate parent method in the super function; if a function name is specified, functions of some implementations, e.g. of the SpiderMonkey already have that name property). As an example, you can examine e.g. this implementation. But that’s already another topic. The main goal is to show, that a correct caller value can be useful for a convenient code reuse implementation without specifying a long parent constructor’s name in the classical approach of that pattern which we discussed in the chapter 7.2 of ES3 series devoted to OOP in ECMAScript:

// much convenient to write
foo: function () {
  return this.super() + " own";
}

// instead of
foo: function () {
  ChildConstructor.superproto.foo.apply(this, arguments) + " own";
}

There is another approach to use the same super method — wrapping each child method with the same name with a special wrapper-function which will set correct this.super value, get the result, restore back this.super and return the result. But, repeat, this is already another story, and now we’re just saying that because of a caller was recognized as error-pron and insecure, it was removed from the strict mode:

"use strict";

(function foo() {
  alert(arguments.caller); // SyntaxError
  alert(foo.caller); // SyntaxError
})();

Notice also another mentioned innovation of ES5 — it is possible to use keywords as property names. That exactly why we were able to use this.super in the examples above, which provides a SyntaxError in ES3, because super is a future reserved keyword. In ES5 we can normally use them:

var foo = {
  function: function () {
    alert(10);
  },
  super: function () {
    this.function();
  }
};

foo.super(); // 10

Duplications of property names in an object initialiser are restricted:

"use strict";

// SyntaxError
var foo = {
  x: 10,
  x: 10
};

// SyntaxError
var bar = {
  get y() {},
  get y() {}
};

Duplications of formal parameters of functions are restricted as well:

"use strict";

// SyntaxError
function foo(x, x) {}

Applied in a strict code, delete operator cannot remove non-configurable properties (i.e. properties having [[Configurable]] attribute as false) and provides SyntaxError or TypeError depending on the case. Actually, a variable, function argument, or function couldn’t be deleted also in ES3 (except the eval context). Here, in strict mode, delete additionally provides errors (including deleting in the eval context):

"use strict";

var foo = {};

function bar(x) {
  delete x; // SyntaxError
}

bar(10);  // SyntaxError

delete foo; // SyntaxError
delete bar; // SyntaxError

Object.defineProperty(foo, "baz", {
  value: 10,
  configurable: false
});

delete foo.baz; // TypeError

// SyntaxError
eval("var x = 10; delete x;"); // in non-strict is OK

As we know a “with” statement in ES3 augments a scope chain of an execution context and restores it back after the evaluation. It does the same in a non-strict mode of ES5, although in the different terminology related with lexical environments which will be discussed in the following chapters.

Statement “with” semantically is used to reference properties of an object without specifying object’s name prefix. It also could be used as e.g. “using namespace” of C++. For example:

namespace("Widget")(function () { with (Widget) {
  init().repaint();
}});

However, because of some “magic” (but actually — just inattentive) confusions — for example, one of The Quiz’s questions, it was decided to remove “with” statement completely from the strict mode. Now it provides a SyntaxError:

"use strict";

// SyntaxError
with ({a: 10}) {
  alert(a);
}

In the strict mode, a this value is not automatically coerced to an object. A this value of null or undefined is not converted to the global object and primitive values are not converted to wrapper objects. The this value passed via a function call (including calls made using Function.prototype.apply and Function.prototype.call) do not coerce the passed this value to an object:

"use strict";

// undefined "this" value,
// but not the global object
function foo() {
  alert(this); // undefined
}

foo(); // undefined

// "this" is a primitive
Number.prototype.test = function () {
  alert(typeof this); // number
};

1..test(); // number

foo.call(null); // null
foo.apply(undefined); // undefined

Undefined value for this can help to avoid cases with using constructors, forgetting new keyword:

// non-strict
function A(x) {
  this.x = x;
}

var a = A(10); // forget "new" keyword

// as a result "a" is undefined,
// because exactly this value is returned
// implicitly from the A function

alert(a); // undefined

// and again created "x" property
// of the global object, because "this"
// is coerced to global object in the
// non-strict in such case

alert(x); // 10

In strict mode, an exception is thrown:

"use strict";

function A(x) {
  this.x = x;
}

// forget "new" keyword,
// error, because undefined.x = 10

var a = A(10);

var b = new A(10); // OK

Sometimes, a “this” value in a function call — as in the example above in the foo function — is used to get the global object from any context:

function global() {
  return this;
}

Now in a strict mode such calls return undefined. To evaluate a code in the global context with exactly this value as the global object can help a so-called indirect eval call. To specify what is indirect eval call, let’s define a direct eval call concept first.

A direct call to the eval function is one that uses exactly a call expression on Reference type value which referenced name component is “eval” and which base component is an environment record.

We will discuss environment records in the following chapters, and now is just good to remind a Reference type from the the chapter 3 of ES3 series devoted to this value. The following example uses a direct call to the eval and evaluates depending on the calling context:

var x = 10;

// a direct call
eval("alert(x)"); // 10

// because call expression is
// applied on the value of Reference type

var evalReference = {
  base: <global environment record>,
  referencedName: "eval",
  strictReference: true // flag, that we are in strict mode
};

// inside a function context
// also can be a direct call to "eval"

(function foo() {
  var x = 20;
  // also a direct call
  eval("alert(x)"); // 20 - from the calling context
})();

All the other variations — are indirect calls to eval and evaluate in the global context including this value as a global object and all variable bindings from the global context. For example:

var x = 10;

(function foo() {

  var x = 20;

  // an indirect call, because a referenced name
  // of a Reference type is value not "eval"

  var get = eval;
  get("alert(x)"); // 10 - from the global context

  // also indirect, because comma returns a
  // function object, so we apply a call
  // expression not to a Reference type value at all

  ("get", eval)("alert(x);"); // again 10

  var window = 100;

  eval("alert(window);"); // 100 - via a direct cal
  get("alert(window);"); // object - via indirect

})();

So this approach can be used in the strict mode to get the global object via this value:

var x = 10;

(function foo() {

  var get = eval;
  var global = get("this");

  alert(this.x); // 20
  alert(global.x); // 10

}).call({x: 20});

Direct and indirect calls to eval are not related exactly with the strict mode. We’ve just considered them in a view of one “issue” related with the strict mode. Generally, this separation on direct and indirect eval calls again is related with security reasons.

Notice, that using already mentioned above Function function, which evaluates its code having only global object in scope chain, in common case won’t help to get global this value in strict mode. Since, again — it just has global object as its environment record, but not the complete semantic of the global context, including this value, which in such calls can be any other object:

"use strict";

var x = 10;

(function test() {
  var foo = {
    x: 20,
    bar: Function("'use strict'; print(x); print(this.x);")
  };
  foo.bar(); // 10, 20
})();

And regarding the issue with getting the correct value of the global object, it is possible to define a simple global constant and use this name binding from any context (although, it can be shadowed by the local variable with the same name):

Object.defineProperty(this, "global", {
  value: this
});

var x = 10;

(function foo() {

  var x = 30;

  alert(x); // 30
  alert(this.x); // 20
  alert(global.x); // 10

  // but var global; will cause an issue

}).call({x: 20});

From the other hand, undefined value for this in a simple function call, can be used for testing, whether we currently are in the strict mode:

"use strict";

function isStrictMode() {
  return !this;
}

if (isStrictMode()) {
  // possibly specific implementation
}

In this chapter we in detail discussed all features related with the “strict mode” of the ECMA-262-5 specification. There is a philosophical dilemma whether such separation on “strict” and “non-strict” is needed — but, this is already another topic. As always, if you have questions or additions, we can discuss them in comments.

  • 4.2.2 The Strict Variant of ECMAScript;
  • 10.1.1 Strict Mode Code;
  • 14.1 Directive Prologues and the Use Strict Directive;
  • 15.1.2.1.1 Direct Call to Eval;
  • Annex C (informative) The Strict Mode of ECMAScript;


Written by: Dmitry A. Soshnikov.
Published on: 2010-06-01


Tags: , , , ,

 
 
 

8 Comments:

  1. Gravatar of Sergey Sergey
    1. June 2010 at 23:41

    Надеюсь появится перевод на русский, потому как не совсем все понятно к сожалению. К примеру это:

    var get = eval;
    get("alert(x)"); // 10 - from the global context

    да и вобще это было единственным местом, где про js можно было почитать на русском и подробно.


  2. Gravatar of Art Art
    2. June 2010 at 03:37

    Hi,

    Thanks for the article!

    While it’s all nice in theory, I’d be useful to know which browsers support this strict mode.

    Thanks!


  3. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    2. June 2010 at 14:20

    @Sergey

    Надеюсь появится перевод на русский

    Пока, к сожалению, не планирую; возможно, позже — когда допишу все части этой новой серии. Но, этим может заняться кто-нибудь другой. Я смогу проверить качество перевода в техническом плане (относительно самого JS имеется в виду); отсюда смогу дать ссылки, как это сделано с китайскими переводами, например.

    потому как не совсем все понятно к сожалению. К примеру это:

    var get = eval;
    get("alert(x)"); // 10 - from the global context

    Суть в том, что есть явный (direct) и неявный (indirect) вызовы eval’a. Вариации неявного вызова описаны в статье; одна из них — это использовать другое имя идентификатора. Главный момент, это то, что неявный вызов исполняется всегда в глобальном контексте, поэтому “x” из примера выше берётся именно оттуда, а не из локального контекста функции.

    да и вобще это было единственным местом, где про js можно было почитать на русском и подробно.

    Ну, все русские (оригинальные) статьи серии ES3 по-прежнему здесь. Возможно, появятся из переводы ES5 серии.

    Dmitry.


  4. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    2. June 2010 at 14:27

    @Art

    I’d be useful to know which browsers support this strict mode

    Currently, the only complete implementation of ES5 is the BESEN engine. I’ve updated the article, mentioning it. It still has some bugs, several of them I’ve posted during writing the article — and glad to see that the implementer has already fixed them. You can download it and test ES5 there now. Hope, some major implementations will follow soon.

    Dmitry.


  5. Gravatar of Mark S. Miller Mark S. Miller
    2. June 2010 at 18:14

    You can track the status of ES5 implementations in progress

    here


  6. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    3. June 2010 at 20:41

    @Mark S. Miller

    You can track the status of ES5 implementations in progress

    Yeah, thanks Mark, that’s useful.

    Dmitry.


  7. Gravatar of kangax kangax
    8. July 2010 at 17:46

    Awesome overview! :)

    But a couple of important corrections:

    1. “eval” and “arguments” not being able to occur as properties — e.g. `({ eval: 1 })` — is a misconception. From what I can see, there’s nothing in the specs that disallows it. The confusion probably comes from the fact that “eval” and “arguments” can NOT occur as /Identifier/ in /PropertySetParameterList/ — `({ set foo(eval, arguments) { } }) /* SyntaxError */` By the way, IIRC, last time I checked, BESEN was incorrectly throwing an error on `({ eval: 1 })`.

    2. Use Strict Directive (being an /ExpressionStatement/ in Directive Prologue) can NOT occur anywhere in the scope of a function (or program body), contrary to what you say. Well, technically it can, but then it’s just an /ExpressionStatement/ consisting of a string literal, not a Use Strict Directive. The special nature of /ExpressionStatement/’s in Directive Prologue is that they occur as the _initial /SourceElement/’s_ in function or program. So `alert(1); “use strict”` is not a strict-mode code, but `”use strict”; alert(1);` is.


  8. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    9. July 2010 at 13:42

    @kangax

    Yeah, good points, thanks.

    Regarding both — these were bugs in BESEN. The second one (with “use strict” position) was fixed earlier, but after the article was written. However, the spec is clear in this case — it is an initial SourceElement.

    The first one is not so easy to catch in spec, but, yeah, obviously, it was also a bug in BESEN, and the spec is also clear here. I’ve talked to BeRo just some minutes ago, it’s fixed now.

    Dmitry.


Leave a Reply

Code: For code you can use tags [js], [text], [ruby] and other.

XHTML: 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>