- Notifications
You must be signed in to change notification settings - Fork574
LanguageFeatures
This is the list of features that are turned on by default.
- Arrow Functions
- Block Scoped Binding
- Classes
- Computed Property Names
- Default Parameters
- Destructuring Assignment
- Iterators and For Of
- Generators
- Modules
- Numeric Literals
- Property Method Assignment
- Object Initializer Shorthand
- Rest Parameters
- Spread
- Template Literals
- Promises
All these features are either part of the official ECMAScript Harmonydraft orproposals unless otherwise noted.
These are no longer part of ES6 and not turned on by default but are considered safe:
And these are only experimental and need to be turned on manually:
- Proper Tail Calls (ES6, but performance)
- Symbols (ES6, but performance?)
- Async Functions (ES8)
- Async Generators (Not part of ES)
- Types (Not part of ES)
- Annotations (Not part of ES)
varsquare=(x)=>{returnx*x;};varsquare2=x=>x*x;varobjectify=x=>({value:x});// Immediate return of an object literal must be wrapped in parenthesesexpect(square(4)).to.be.eql(16);expect(square2(4)).to.be.eql(16);expect(objectify(1)).to.be.eql({value:1});
ES6 Spec:Arrow Functions
Block scoped bindings provide scopes other than the function and top level scope. Thisensures your variables don't leak out of the scope they're defined:
{consttmp=a;a=b;b=tmp;}alert(tmp);// error: 'tmp' is not defined.
It's also useful for capturing variables in a loop:
letfuncs=[];for(letiof[4,5,6]){funcs.push(function(){returni;});}for(varfuncoffuncs){console.log(func());// 4, 5, 6}
ES6 Spec:Let and Const Declarations
This implements class syntax and semantics as described in the ES6 draft spec. In earlierversions of Traceur we had more feature rich classes but in the spirit of Harmony we havescaled back and are now only supporting the minimal class proposal.
Classes are a great way toreuse code. Several JS libraries provide classes and inheritance, but they aren'tmutually compatible.
classCharacter{constructor(x,y){this.x=x;this.y=y;}}classMonsterextendsCharacter{constructor(x,y,name){super(x,y);this.name=name;this.health_=100;}attack(character){super.attack(character);this.health_+=10;}getisAlive(){returnthis.health_>0;}gethealth(){returnthis.health_;}sethealth(value){if(value<0)thrownewError('Health must be non-negative.');this.health_=value;}}varmyMonster=newMonster(5,1,'arrrg');expect(myMonster.health).to.be.eql(100);expect(myMonster.isAlive).to.be.eql(true);expect(myMonster.x).to.be.eql(5);myMonster.health=10;expect(myMonster.health).to.be.eql(10);expect(myMonster.name).to.be.eql('arrrg');
Here's an example of subclassing an HTML button:
classCustomButtonextendsHTMLButtonElement{constructor(){this.value='Custom Button';}// ... other methods ...}varbutton=newCustomButton();document.body.appendChild(button);
Warning This is currently not supported.
ES6 Spec:Classes
varx=0;varobj={[x]:'hello'};expect(obj[0]).to.be.eql('hello');
Default parameters allow your functions to have optional arguments without needing to checkarguments.lengthor check forundefined.
functionf(list,indexA=0,indexB=list.length){return[list,indexA,indexB];}expect(f([1,2,3])).to.be.eql([[1,2,3],0,3]);expect(f([1,2,3],1)).to.be.eql([[1,2,3],1,3]);expect(f([1,2,3],1,2)).to.be.eql([[1,2,3],1,2]);
ES6 Spec:Default Parameters
Destructuring assignment is a nice way to assign or initialize several variables at once.
var[a,[b,c],[d]]=['hello',[', ','junk'],['world']];expect(a+b+d).to.be.eql('hello, world');
It can also destructure objects:
varpt={x:123,y:444};varrect={topLeft:{x:1,y:2},bottomRight:{x:3,y:4}};// ... other code ...var{x, y}=pt;// unpack the pointvar{topLeft:{x:x1,y:y1},bottomRight:{x:x2,y:y2}}=rect;expect(x+y).to.be.eql(567);expect([x1,y1,x2,y2].join(',')).to.be.eql('1,2,3,4');
ES6 Spec:Destructuring Assignment
Iterators are objects that can traverse a container.It's a useful way to make a class work inside a for of loop. The interface is similarto theiterators-interface.Iterating with a for of loop looks like:
varres=[];for(varelementof[1,2,3]){res.push(element*element);}expect(res).to.be.eql([1,4,9]);
You can also create your own iterable objects. Normally this is done via theyieldkeyword (discussed below inGenerators but it could be done explicitly byreturning an object that hasSymbol.iterator):
functioniterateElements(array){return{[Symbol.iterator]:function(){varindex=0;varcurrent;return{next:function(){if(index<array.length){current=array[index++];return{value:current,done:false};}return{value:undefined,done:true}}};}};}// Usage:varg=iterateElements([1,2,3]);varres=[];for(varaofg){res.push(a);}expect(res).to.be.eql([1,2,3]);
Generators make it easy to create iterators. Instead of tracking state yourselfand implementingSymbol.iterator, you just useyield (oryield* to yield each elementin an iterator).
// A binary tree class.functionTree(left,label,right){this.left=left;this.label=label;this.right=right;}// A recursive generator that iterates the Tree labels in-order.function*inorder(t){if(t){yield*inorder(t.left);yieldt.label;yield*inorder(t.right);}}// Make a treefunctionmake(array){// Leaf node:if(array.length==1)returnnewTree(null,array[0],null);returnnewTree(make(array[0]),array[1],make(array[2]));}lettree=make([[['a'],'b',['c']],'d',[['e'],'f',['g']]]);// Iterate over itvarresult=[];for(letnodeofinorder(tree)){result.push(node);// a, b, c, d, ...}expect(result).to.be.eql(['a','b','c','d','e','f','g']);
A generator function needs to be annotated asfunction* instead of justfunction.
ES6 Spec:Generators
Modules are mostly implemented,with some parts of the Loader API still to be corrected. Modules try to solve many issuesin dependencies and deployment, allowing users to create modules with explicit exports, importspecific exported names from those modules, and keep these names separate.
// Profile.jsexportvarfirstName='David';exportvarlastName='Belle';exportvaryear=1973;
// ProfileView.jsimport{firstName,lastName,year}from'./Profile.js';functionsetHeader(element){element.textContent=firstName+' '+lastName;}// rest of module
These modules can be loaded in several ways. We'll just show a couple of ways to get you started.
In a Web page you can usescript tags withtype="module":
<scriptsrc="../bin/BrowserSystem.js"></script><script>System.loadScriptTypeModule();</script><scripttype="module"src="ProfileView.js"></script>
See for example,async.html.
To load modules dynamically, useSystem.import:
<scriptsrc="../bin/BrowserSystem.js"></script>...<script>System.import('./repl-module.js').catch(function(ex){console.error('Internal Error ',ex.stack||ex);});</script>
See for examplerepl.html.
OurSystem is primarily used to test the our compiler. A production readySystem is available insystemjs.
varbinary=[0b0,0b1,0b11];expect(binary).to.be.eql([0,1,3]);varoctal=[0o0,0o1,0o10,0o77];expect(octal).to.be.eql([0,1,8,63]);
ES6 Spec:Numeric Literals
Method syntax is supported in object initializers, for example seetoString():
varobject={value:42,toString(){returnthis.value;}};expect(object.toString()).to.be.eql(42);
ES6 Spec:Object Initializer Shorthand
This allows you to skip repeating yourself when the property name and property value are the same inan object literal.
functiongetPoint(){varx=1;vary=10;return{x, y};}expect(getPoint()).to.be.eql({x:1,y:10});
ES6 Spec:Object Initializer Shorthand
Rest parameters allows your functions to have variable number of arguments without using thearguments object.The rest parameter is an instance ofArray so all the array methods just work.
functionpush(array, ...items){items.forEach(function(item){array.push(item);});}varres=[];push(res,1,2,3);expect(res).to.be.eql([1,2,3]);
ES6 Spec:Rest Parameters
The spread operator is like the reverse ofrest parameters. It allows you toexpand an array into multiple formal parameters.
functionpush(array, ...items){array.push(...items);}functionadd(x,y){returnx+y;}varnumbers=[4,38];expect(add(...numbers)).to.be.eql(42);
The spread operator also works in array literals which allows you to combine multiple arrays more easily.
vara=[1];varb=[2,3,4];varc=[6,7];vard=[0, ...a, ...b,5, ...c];expect(d).to.be.eql([0,1,2,3,4,5,6,7]);
ES6 Spec:Spread Operator
varname='world';vargreeting=`hello${name}`;expect(greeting).to.be.eql('hello world');
ES6 Spec:Template Literals
We have a polyfill of Promises. It is used by themodule loader and theasync functions.
functiontimeout(ms){returnnewPromise((resolve)=>{setTimeout(resolve,ms);});}timeout(100).then(()=>{console.log('done');});
ES6 Spec:Promises
vararray=[for(xof[0,1,2])for(yof[0,1,2])x+''+y];expect(array).to.be.eql(['00','01','02','10','11','12','20','21','22']);
ES6 Spec:Array Comprehension
Lazy computed comprehensions.
varlist=[1,2,3,4];varres=(for(xoflist)x);varacc='';for(varxofres){acc+=x;}expect(acc).to.be.eql('1234');
ES6 Spec:Generator Comprehension
Calls in tail position do not grow the stack. Proper tail calls allow you to write in a functional orcontinuation passing style without having to worry about stack overflows.
functiong1(n,m){returnn===0 ?m :g2(n-1,n+m);}functiong2(n,m){returnn===0 ?m :g1(n-1,n+m);}functionf(n){returng1(n,0);}functionsum(n){returnn*(n+1)/2;}assert.equal(f(100000),sum(100000));
// --symbolsvars=Symbol();varobject={};object[s]=42;expect(object[s]).to.be.eql(42);
Async functions allow you to write asynchronous non-blocking code without writingcallback functions, which don't compose well. With async functions, you can useJavaScript control flow constructs that you're used to, inline with the rest of your code.
An async function can contain await expressions. The operand of the await expression istreated asPromise and when the promise is fulfilled theexecution continues.
functiontimeout(ms){returnnewPromise((resolve)=>{setTimeout(resolve,ms);});}asyncfunctionasyncValue(value){awaittimeout(50);returnvalue;}(asyncfunction(){varvalue=awaitasyncValue(42).catch(console.error.bind(console));assert.equal(42,value);done();})();
ES7 Proposal:Async Functions
Async generators allow you to write non-blocking code that asynchronously returns multiple values.Unlike an async function that eventually resolves to one value, an async generator produces ofsequence of values much like an iterator. Unlike iterators, however, which are consumed while theconsuming party is in charge of control, async generators push their values to their consumers,named observers, and remain in charge of control. For the observing part, there is also a languageconstruct, the for on loop.
An async generator is a generator that can contain await expressions. As with async functions, theoperand of the await expression is treated asPromise and when the promiseis fulfilled the execution continues.
functiontimeout(ms){returnnewPromise((resolve)=>{setTimeout(resolve,ms);});}asyncfunction*asyncStream(){vari=0;while(true){awaittimeout(50);yieldi;++i;}}(asyncfunction(){varcount=0;for(valueonasyncStream()){ count+=value;if(value===10){break;// stops the async generator as well}}assert.equal(count,55);// 55 = 1 + 2 + ... + 10done();})();
ES7 Proposal:Async Generators
Offical Strawman:Types
// --annotationsimport{Anno}from'./resources/setup.js';@AnnofunctionSimple(){}assertArrayEquals([newAnno],Simple.annotations);