How to make sure ES3 programs will run in an ES5 engine?
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 valu开发者_如何学Pythone is passed without modification as the
this
value. This is a change from Edition 3, where aundefined
ornull
thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as thethis
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?
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:
- If the function code is strict code, set the ThisBinding to thisArg.
- Else if thisArg is null or undefined, set the ThisBinding to the global object.
- ...
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.
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.
精彩评论