views:

159

answers:

1

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?

+3  A: 

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.

kangax
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.
Pumbaa80
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
@kangax: 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.
Pumbaa80
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 — http://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