6

So ECMAScript 5 introduces some incompatibilities with ECMAScript 3.


Example:

Many articles have been written stating that this === null || this === undefined is possible in ES5 strict mode:

"use strict";
(function () {
    alert(this); // null
}).call(null);

But, what the standard really suggests is that ES5 engines also allow this in non-strict mode:

15.3.4.3 ... The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.

Currently, IE9 is the only browser that actually implements ES5 this way, and it turns out that this may break current scripts. Great.


Annix E of ES5 spec lists dozens of other incompatibilities.

So what's the best way to make sure that our well-tried ES3 scripts will continue running flawlessly? Some kind of automated test-suite? Will we have to test it all manually?

2 Answers 2

6

For the record, the questioner's interpretation of ES5 15.3.4.3 is incorrect. Any call to a non-strict function in ES5 should be observably the same as in ES3. The global object is still passed into any non-strict function that is called with null or undefined as the this value.

The missing piece of the analysis is 10.4.3 "Entering Function Code":

The following steps are performed when control enters the execution context for function code contained in a function object F, a caller provided thisArg, and a caller provided argumentsList:

  1. If the function code is strict code, set the ThisBinding to thisArg.
  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
  3. ...

ES3 specified that the caller was responsible for substituting the global object for a null or undefined this value. ES5 specifies that the callee has that responsiblity (if it isn't a strict mode function). For non-strict code this is not an observable difference. The specification change only makes a difference when the callee is a strict function.

2
  • Typo: “undefined as the the value” Feb 17, 2012 at 21:51
  • @AxelRauschmayer—ES5 has to work that way because the caller doesn't necessarily know whether the callee is in strict mode or not. So passing the thisArg from the call and letting the callee sort it out makes sense. :-)
    – RobG
    Oct 13, 2014 at 3:41
4

Automated test suite is certainly a good idea.

Since more and more implementations implement ES5 now, running the test suite for your script/library/application in newer browsers is a good way to ensure compatibility.

I have an ES5 compatibility table, listing level of support of some of the more popular implementations. Its not exhaustive, but it shows overall direction — that latest IE, WebKit, Chrome and Firefox all have quite good ES5 support. For a complete conformance test, you can always run official ES5 test suite (which I have online for convenience right here).

If there's no test suite (which should really exist, as it is very useful for few other reasons), you can just run script/library/application in one of the newer (ES5 conforming) implementations and see what works and what fails.

Consulting Annex E is another way to go. Note that even though the list seems quite large, it's not as bad as it seems. One of the goals of ES5 was to make transition from ES3 more or less painless, moving more radical changes into the realm of opt-in strict mode.

Many compatibility changes from that list are likely to go unnoticed. Take for example, change in 15.1.1, where global undefined, NaN and Infinity are now read-only. Considering that sane applications do not reassign these global properties — except by mistake — this change is more of a pleasant "error-catcher" rather than "app-breaker".

Another liekly innocent change is in 15.10.2.12, where whitespace character class (\s) now also matches <BOM> (U+FEFF) character. Considering all the deviations in current implementations (even in regards to ES3), this change is likely to go unnoticed in majority of applications.

However, there are also more dangerous changes, such as that in parseInt and how it no longer treats strings beginning with 0 as octal values. parseInt('010') should not produce 8 anymore (although some implementations chose to deliberately violate that behavior). And still, relying on parseInt without second "radix" argument was never a good practice. So if your application always specifies radix, there's nothing to worry about.

So consult Annex E, test your script in newer implementations (preferably, multiple ones), and follow best practices. That's a good way to ensure compatibility.

4
  • Your test suite is really good stuff. However, I'm afraid it won't help with my particular situation. Basically, my company needs to make sure our legacy scripts don't cause any issues in our customers' installations. We're talking about hundreds and hundreds of scripts here, and manually checking each and every bit of functionality looks like a lot of pain. ("Unit tests? What's that?") Currently, I'm afraid we're quite simply waiting for bug reports. Oct 23, 2010 at 7:41
  • How about running scripts through JSLint? One by one, little by little. JSLint might not cover all of the compat-sensitive changes, but it will certainly get you close. It will warn about parseInt w/o radix, and about property names as keywords (e.g. ({ if: 1 })), and others.
    – kangax
    Oct 23, 2010 at 20:08
  • Unfortunately, JSLint will report thousands of errors, and occasionally refuse to continue (e.g. when hitting void) even though the scripts run fine in ES3. As a matter of fact, I've made some JSLint mods in the past, and I'm thinking about adding some ES5 stuff, too. However, some of the incompatibilities (7.8.5/1, 10.4.2, 10.6/2, 15.3.4.3, 15.3.4.4, 15.10.2.12) are very hard to find at parse-time. Oct 25, 2010 at 9:01
  • I was just thinking the same — that quite few ES5 changes can not be caught via static (lexical) analysis. So it would be challenging (if at all possible) to write comprehensive compatibility lint tool. Speaking of 10.4.2 — indirect eval — note that a lot of newer (and not so new) browsers have already been following ES5 behavior for a while now — kangax.github.com/jstests/indirect_eval_call_test so that "change" likely won't be a concern (ES5 sort of codifies de-facto standard there, rather than introduce completely different behavior).
    – kangax
    Oct 25, 2010 at 13:58

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.