EcmaScript is the standardized scripting language that JavaScript (and some other languages, like ActionScript) implement. If you think EcmaScript is a terrible name, you’re not alone. Brendan Eich, the original developer of JavaScript, once wrote that the name EcmaScript sounds like a skin disease. Naming aside, JavaScript is one of the most important languages in existence today. Every browser has a JavaScript interpreter, JavaScript on the server is becoming ever more popular, and now it’s possible to use JavaScript for desktop (Chrome Apps), nativish mobile (PhoneGap) and native Windows 8 apps. A new version of EcmaScript will have a broad impact on web development.
The current version of EcmaScript supported in modern browsers is ES5 (with some ES6 support). ES5 drives a lot of developers mad. Folks coming from the backend development space find ES5 lacks some pretty basic language features. As such, several workarounds have emerged. TypeScript is very popular in the .NET world (and here at Wintellect) and CoffeeScript is kind of a big deal™ in the Ruby community. Both TypeScript and CoffeeScript provide syntactic sugar on top of ES5 and then are transcompiled into ES5 compliant JavaScript. ES6 will tackle many of the core language shortcomings addressed in TypeScript and CoffeeScript.
There are quite a few new features in ES6, many still in draft form. In this post I’ll cover classes, Arrow Functions, Modules, Block Scoping, and Promises.
There are several options to approximate classes in ES5. The most common approach is probably the special constructor function like this http://jsfiddle.net/noelstieglitz/a5heA/
function Car( make ) { //approximate a class/constructor this.make = make; this.currentSpeed = 25; this.printCurrentSpeed = function(){ //expose a function console.log(this.make + ' is going ' + this.currentSpeed + ' mph.'); } } // Instantiate a new car var moderatelyPricedCar = new Car( "Kia"); moderatelyPricedCar.printCurrentSpeed(); //Kia is going 25 mph.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Approximate no more! ES6 introduces language support for classes (class keyword), constructors (constructor keyword), and the extend keyword for inheritance. The developer’s intent is much more clear using the ES6 syntax. http://www.es6fiddle.net/hrut24r0/
class Car { constructor(make) { //constructors! this.make = make; this.currentSpeed = 25; } printCurrentSpeed(){ console.log(this.make + ' is going ' + this.currentSpeed + ' mph.'); } } class RaceCar extends Car { //inheritance constructor(make, topSpeed) { super(make); //call the parent constructor with super this.topSpeed = topSpeed; } goFast(){ this.currentSpeed = this.topSpeed; } } let stang = new RaceCar('Mustang', 150); stang.printCurrentSpeed(); stang.goFast(); stang.printCurrentSpeed();
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
If you love prototypical inheritance, no need to fret. You can still use prototypical inheritance in ES6.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Many features in ES6 could fundamentally change how new JavaScript applications are architected. Arrow functions is not going to fundamentally change anything. Still, it’s one of my favorite features. Arrow functions provide two features: lexical scoping of the this keyword and less ceremony when defining an anonymous function.
Without arrow functions, every function defines a this value. No more will you need to reassign this like you have probably done in the next code snippet:
http://jsfiddle.net/noelstieglitz/wfJL5/
function Car() { var self = this; //locally assign this that can be closed over self.speed = 0; setInterval(function goFaster() { //this has a different scope, but we can use the self variable to reference the parent "this" self.speed += 5; console.log('now going: ' + self.speed); }, 1000); } var car = new Car();
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
The above snippet could be rewritten as
http://www.es6fiddle.net/hrw5xz4f/
function Car() { //Note, we could use the new Class feature in ES6 instead this.speed = 0; setInterval(() => { this.speed += 5; //this is from Car console.log console.log('now going: ' + this.speed); }, 1000); }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
If you’re a C# developer who has ever used lambda expressions, the syntax will feel very familiar. Check out the ecmascript.org wiki regarding arrow functions:
Hard to beat C# and CoffeeScript here (we want the unparenthesized single-parameter form as in C#).
TC39 should embrace, clean-up, and extend rather than re-invent or compete with de-facto and nearby de-jure standards.
I can’t agree more. Here is some ES5 code that will calculate the square of every value in an array and log the value to the console http://jsfiddle.net/noelstieglitz/LLDBp/1/
var x = [0,1,2]; x.map(function (x) { //anonymous function console.log(x * x); });
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
In comparison, the ES6 arrow function syntax is really clean http://www.es6fiddle.net/hruu11fz/
let x = [0,1,2]; x.map(x => console.log(x * x)); //arrow function
Modules have the potential to radically change how many JavaScript applications are structured and standardize a best practice in some already modular applications. Modules in ES6 provide a way to load and manage dependencies via the new import and export keywords. There are a few good solutions in ES5, namely 3rd party libraries like CommonJS or node modules. Modularity is a such an important concept for large applications, that it makes sense to include it as a core language feature. The goals for ES6 modules are pretty lofty (from the ecmascript wiki, highlight is my own):
Read more about modules on Axel’s excellent post. Here is a code snippet from Axel showing how to load a dependent module:
<module> import $ from 'lib/jquery'; var x = 123; // The current scope is not global console.log('$' in window); // false console.log('x' in window); // false // `this` still refers to the global object console.log(this === window); // true </module>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Scoping in JavaScript is confusing for developers with a C/C#/Java background. Hoisting can add to that confusion. In ES5, variables are either globally or locally function scoped. The lack of block scoping has caused confusion in ES5, and resulted in some interesting patterns to achieve block scope. In ES6, you can use the new let keyword to achieve block scoping. http://www.es6fiddle.net/hrut3qnv/
var num = 0; //globally scoped for (let i = 0; i < 10; i++) { //i is block scoped num += i; console.log('value of i in block: ' + i); } console.log('Is i defined here?: ' + (typeof i !== 'undefined')); //Is i defined here?: false
Promises provide a mechanism to handle the results and errors from asynchronous operations. You can accomplish the same thing with callbacks, but promises provide improved readability via method chaining and succinct error handling. Promises are currently used in many JavaScript libraries. RSVP.js, Q.js, and the $q service in Angular are just a few of many examples. Here is an example from the RSVP.js docs:
getJSON("/api/employee/1").then(function(post) { return getJSON(post.commentURL); }).then(function(comments) { //you could chain multiple then statements // proceed with access to employee }).catch(function(error) { //succinct error handling // handle errors in either of the two requests });
You can also wait for all promises to complete:
var promises = [2, 3, 5, 7, 11, 13].map(function(id){ return getJSON("/post/" + id + ".json"); }); RSVP.all(promises).then(function(posts) { // posts contains an array of results for the given promises }).catch(function(reason){ // if any of the promises fails. });
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
This pattern will look familiar to those who have written multithreaded C# code (the last example is like the WaitHandle::WaitAll method). Unfortunately, each library has a slightly different implementation. It’s confusing to fully grok the Q.js library only to find that the Angular $q service only provides a subset of the same functionality. ES6 will standardize promises and remove the external dependencies currently required to use promises. Below is a partial list and description of some of the ES6 promise functionality. Read more ES6 promises here.
I can’t describe it any better than the Mozilla docs: Returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a then method), the returned promise will “follow” that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value.
This method is really useful if you are dealing with existing functions or services that don’t return a promise. If the value passed in is a promise, cast returns the value, otherwise the value is coerced to a promise. Either way, you can deal with the result as a promise.
Promise.race returns the first promise in the iterable to resolve. Note the use of arrow functions. 🙂
http://www.es6fiddle.net/hruy6vlb/
var p1 = new Promise((resolve, reject) => setTimeout(resolve, 400, "one")); var p2 = new Promise((resolve, reject) => setTimeout(resolve, 200, "two")); Promise.race([p1, p2]).then(function(value) { console.log(value); //two });
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
The Promise.all method returns a promise when all promises in the iterable have completed.
http://www.es6fiddle.net/hruyss3j/
var p1 = new Promise((resolve, reject) => setTimeout(resolve, 400, "one")); var p2 = new Promise((resolve, reject) => setTimeout(resolve, 200, "two")); Promise.all([p1, p2]).then(function(value) { console.log(value); //one, two });
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/white-space: pre;/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Read more about promises in this fantastic tutorial by Jake Archibald.
Current support for ES6 is quite limited and a lot of the ES6 spec is still in draft form. We can look forward to these features (and much more) in the near future, but I wouldn’t recommend using them now. In the meantime, I recommend using TypeScript (or CoffeeScript, or Traceur, or, etc.) to work around some of the current limitations in ES5.
Cloud management is difficult to do manually, especially if you work with multiple cloud…
Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…
https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…
FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…
Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…
In the intricate landscape of modern business, compliance is both a cornerstone of operational integrity…
View Comments
Note that Promise.resolve is apparently being replaced with Promise.cast, and Promise.cast will be no more. Of course that didn't stop Chrome 23 and Opera 19 from prematurely releasing versions of Promises with .cast on them, so it's probably good to be aware of this change.
Why are you using `.map()` to call `console.log()`? It would be better to either each `.forEach()`, or log the resulting array.
Thanks for the writeup.
Michael - yes, new for ES6. " An identifier followed by an argument list and body defines a method. A “method” here is simply a function property on some object." Check out http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
I thought that behind ES6 'extends' keyword there is a prototypal way of doing inheritance or what else could be behind this keyword in JS? I guess the prototypal way is the only way to mimic pseudo classical inheritance.
There are other ways such as concatenation (mixins) or functional inheritance but I don't think that the extend is ever meant to provide a way for these. It is more likely to be a keyword which makes prototypal inheritance easier or classical.
"If you love prototypical inheritance, no need to fret. You can still use prototypical inheritance in ES6."
I thought that behind ES6 'extends' keyword there is a prototypal way of doing inheritance or what else could be behind this keyword in JS? I guess the prototypal way is the only way to mimic pseudo classical inheritance.
There are other ways such as concatenation (mixins) or functional inheritance but I don't think that the extend is ever meant to provide a way for these. It is more likely to be a keyword which makes prototypal inheritance easier and provides the 'classical OOP' keyword: extends for people having a different coding background and coming from languages like JAVA.
If you use Rails, you can start using ES6 in your projects today.
http://blog.kwanso.com/using-ecmascript-6-with-rails-4-2-projects/
If you use Rails, you can start using ES6 in your projects today.
http://blog.kwanso.com/using-ecmascript-6-with-rails-4-2-projects/
Use ES6 now - Preprocess your ES6 code to convert it to ES5 using https://babeljs.io/docs/learn-es6/
Thanks for the tute
Use ES6 now - Preprocess your ES6 code to convert it to ES5 using https://babeljs.io/docs/learn-es6/
Thanks for the tute
Just being a little pedantic here but your 'old' example under Arrow Functions don't really work, this kind of put me off reading the rest. All functions have .bind() along with other methods. You would simply bind the this value of your anon function. Other methods such as arrays forEach and map allow you to pass a value to set as this.
function Car() {
this.speed = 00;
setInterval(function () {
this.speed += 5;
console.log('now going: ' + this.speed);
}.bind(this), 1000);
}
var car = new Car();
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind