ECMAScript 4: The missing version
In your build tools, you may have noticed that you have an ECMAScript 3 target, and 5 and up, but never a 4. Why is that?
I thought it would be fun to dive into ECMAScript 4 a bit and see what we didn’t get.
A brief history
According to Wikipedia, the first draft of ECMAScript 4 was dated February 1999. The original target for completion was August 2008.
ECMAScript 4 was very ambitious, and added a ton of features that were perceived as important and missing from ECMAScript 3. It also ‘fixed’ a number of things in the previous version, making it backwards incompatible in various ways.
ES4 was met with a bunch of controversies, and lacked sufficient support from browser vendors to be released and was ultimately abandoned.
In 2008 the standard was pronounced dead, and ES3.1 was renamed to ES5, which was a much more conservative and incremental update to ECMAScript.
The closest thing we had for ES4, was probably Flash Actionscript 3. There was a point during the release of AS3 that some of us thought that Flash and the Web was eventually going to converge.
For more details on politics and history of ES4, check out this great article on the auth0 blog.
What could have been?
Classes
Classes eventually landed in ES6, but here’s how it might have looked like earlier:
class C {
var val
var number = 500;
const pi = 3.14
// A function
function f(n) { return n+val*2 }
// Getters and setters
function set foo(n) {
val = n;
}
function get foo() {
return val;
}
}
The syntax here is pretty different, but another notable is that these classes had properties and constants. Field declarations are currently ‘experimental’, so we almost caught up here.
Another surprising thing is that there is no this
. Instead of variables being
global by default, ES4 would first look in the class scope before checking higher
scopes.
ES4 also had the following keywords for class members:
static
final
private
,protected
,public
.prototype
, to define class members on its prototype. Not sure what the use-case is, but it’s there.
Interfaces
ES4 introduced interfaces, which is something we don’t have today (unless you use Typescript):
interface MyInterface {
function foo();
}
Strict typing
ES4 introduced strict typing:
function add(a: int, b:int): int {
return a + b;
}
It also had the type
keyword similar to Typescript and union types. A typescript
union like the following:
let a : number | string;
Is written as follows in ES4:
var a: (number, string)
ES4 also had generics:
class Wrapper<T> {
inner: T
}
Like 👍
By default types in ES4 had to be exact types, and not a superset. Using the
like
keyword you can make this less restrictive:
function getCell(coords: like { x: int, y: int }) {
}
This probably exists because in ES4 types were Nominal and not Structural like Typescript.
New types
In current ES we have booleans, objects, arrays, number, BigInt, but ES4 was going to introduce:
byte
int
unit
double
decimal
Of those, only the decimal type is in the planning today, and it will eventually probably look like:
const allowance = 1.50m
This m
suffix also existed in ES4, and stands for “money”.
triple-quoted strings.
To encode a string like: Hello my name is "Evert"
in ES4, you could use triple-quotes:
const hi = """Hello my name is "Evert"""";
Packages
Packages are a bit like what we have now with modules. Packages can be imported, but unlike ES6 modules, namespaces are more like a global naming system.
If a class is defined as :
package com.evertpot {
// Private
internal const foo = 5;
class MyClass {
}
}
Then you could use this class as follows:
const myObj = com.evertpot.MyClass;
Or:
import * from com.evertpot;
const myObj = MyClass;
As far as I know the standard doesn’t define a relationship between namespaces and where the files can be loaded from.
Generic functions
Generic functions are not parameterized functions, they resemble “Overloaded functions” in typescript a bit, but they’re not quite the same and much more powerful.
Example:
class Foo {
generic function addItem(x);
function addItem(x: int) {
}
function addItem(x: number) {
}
}
In the above example, I can call addItem
with either a int
or number
, and
the correct implementation will be picked at run-time.
E4X
While E4X was technically an extension to ES4, I think it deserves a mention.
E4X stands for ECMAScript for XML, and while that might not sound very exciting, take a look at a code snippet:
const myClass = 'welcome';
const name = 'Evert';
const foo = <div class={myClass}>{"Hello " + name }</div>;
Looks familiar?
Although not quite the same as JSX, it’s becoming clear that this might have been a part of JSX’s origin story.
While ES4 never landed, E4X actually worked in Firefox, until it was removed in Firefox 10.
More features
let const
as a syntax for block-level constants. In ES5 and upconst
is already block-scope.- Generators (
yield
). - Tail-calls
- Namespaced properties, classes and everything to avoid collisions, much like XML namespaces.
How would you load it?
Because Ecmascript 4 would break backwards compatibility, it would be important to tell a browser to interpret a script as ES4:
<script type="text/javascript;version=4" src="..."></script>
This is not unlike what we do with modules today:
<script type="module" src="..."></script>
Afterword
I hope this was an interesting view in the Javascript that could have been. Although we are slowly catching up with newer ECMAScript versions and tools like Typescript and JSX preprocessors, we’re still not quite at 2007’s vision for ECMAScript.
Perhaps if ES4 landed, fewer people would need complex build tools like Babel, Webpack and Typescript.