On Github impatient / es6-midwest-io
Scott Dillender (@smimp)
Interest in this after listening to some Javascript Jabber episodes on it Mention your version grunt traceurWe're at a point where we can replicate a large chunk of the functionality inside of current ECMAScript version (ES 5). The last vestige of pre-ES5 environment is IE8.
ES6 is the next iteration of javascript. Members of the TC39 working group review proposals and decide on what should be included in the next version of the language. The group is comprised of members from various tech companies. Bring up bytecode for the web and how transpilers are the future. DSL's for javascript.We're finally to a point where all of the major browsers will be on a relatively frequent release cycle.
With features added in ES5, most of the features in ES6 can be implemented with a polyfill or transpiling.
Many more depending on what you're actually looking for. https://github.com/addyosmani/es6-tools
An ES6 repl can be found at: http://google.github.io/traceur-compiler/demo/repl.html
var es6 = 'es6'; console.log(`hello ${es6} world`);
Expressivity - Fewer words, more meaning
function rest(initialParameter, ...restOfParameters) { console.log(initialParameter,restOfParameters); }; rest(1,2,3,4); //1,[2,3,4]
function unrest(a,b) { console.log(a,b); } function restEnd(primaryFunction) { return function() { var argSize = arguments.length; return primaryFunction.call(this, arguments[0], [].slice.call(arguments,1) ); } } restEnd(unrest)(1,2,3,4); //1,[2,3,4]
var a = Proxy({}, { get: function(obj, prop) { console.log("get arguments", arguments); return obj[prop]; }, set: function(obj, prop, newVal) { console.log("Calling set with ", arguments); obj[prop] = newVal; } } ); a.eek = 'bam'; Returns: "Calling set with " Arguments {0: Object, 1: "eek", 2: "bam", 3: Object, 2 more…}
var numberator = function*(base) { while(base < 4) { yield ++base; } return ++base; }; //Array comprehension console.log([for ( x1 of numberator(0)) x1]); //no longer lazy //[1,2,3,4]
var numberator = $traceurRuntime.initGeneratorFunction(function $__22(base) { return $traceurRuntime.createGeneratorInstance(function($ctx) { while (true) switch ($ctx.state) { case 0: $ctx.state = (base < 4) ? 1 : 5; break; case 1: $ctx.state = 2; return ++base; case 2: $ctx.maybeThrow(); $ctx.state = 0; break; case 5: $ctx.returnValue = ++base; $ctx.state = -2; break; default: return $ctx.end(); } }, $__22, this); });
Esprima repl can be found at http://esprima.org/demo/parse.html
;
yields
{ "type": "EmptyStatement" }
var a = function(one) { console.log(1); };
yields
{ "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "a" }, "init": { "type": "FunctionExpression", "id": null, "params": [ { "type": "Identifier", "name": "one" } ], "defaults": [], "body": { "type": "BlockStatement", "body": [ { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "MemberExpression", "computed": false,
"object": { "type": "Identifier", "name": "console" }, "property": { "type": "Identifier", "name": "log" } }, "arguments": [ { "type": "Identifier", "name": "one" } ] } } ] }, "rest": null, "generator": false, "expression": false } } ], "kind": "var" }
We'll eschew some of the information in favor displaying it more compactly.
If you go down this path, it appears unwieldy, but with the proper tools/libraries you can handle it, within reason.
var sum = (a,b) => {return a + b; } //or var sum = (a,b) => a+b;
var sum = function(a,b) { return a+b; }
var sum = function(a,b) { return a+b; }.bind(this);
var recast = require('recast'); var Visitor = recast.Visitor; var Arrow = Visitor.extend( { visitArrowFunctionExpression: function(arrow) { return b.callExpression( b.memberExpression( b.functionExpression(null, arrow.params, this.visit(fixBody(arrow.body) ) ), b.identifier('bind'),false), [b.thisExpression()]); } }); var ast = recast.parse(code); new Arrow().visit(ast); var output = recast.print(ast).code; console.log(output);
var fixBody = function(body) { if(body.type !== Syntax.BlockStatement) { return b.blockStatement([b.returnStatement(body)]); } return body; };
var test = function(a=[1,0],b=1) { console.log(a,b); }; test() //[1,0] 1
var {username, password} = { password: '123456', username: 'elpmaxe' }; console.log(username); //elpmaxe console.log(password); //123456
var [first, second, third] = ['zero','one','two','three']; console.log(first); //zero console.log(second); //one console.log(third); //two
var generator = function*(initial) { var individual = initial.split(''); var i =0; while( i< individual.length -1) { yield individual[i++]; } return individual[i]; }; var a = generator('testMe'); console.log(a.next()) //Object {value: "t", done: false} console.log(a.next()) //Object {value: "e", done: false} console.log(a.next()) //Object {value: "s", done: false} console.log(a.next()) //Object {value: "t", done: false} console.log(a.next()) //Object {value: "M", done: false} console.log(a.next()) //Object {value: "e", done: true}
const always= 'always'; if(1 === 1) { let x = 2; } always = 'not-always'; //traceur lets you do this console.log(x); //reference error undefined
var a = [1,2,3] //Array comprehensions console.log([ for (x of a) x ]); //Generator comprehension var b = ( for (x of a) if(x %2) x ); console.log(b.next()) //Object {value: 1, done: false} console.log(b.next()) //Object {value: 3, done: false} console.log(b.next()) //Object {value: undefined, done: true}
var a = [1,2,3,4]; var sum = function(first,second, third,fourth) { console.log(fourth); //4 return Array.from(arguments). reduce( (a, b) => a+b ); }; console.log(sum(...a)); //10
var buildFlightUrl = function({flightType,departure }) { return `http://flights.com/${flightType}/date/${departure}` } console.log(buildFlightUrl({flightType:'roundTrip', departure: '2014-07-16'})); //http://flights.com/roundTrip/date/2014-07-16
var isFocusable = (elem) => elem && elem.tabIndex >= 0; var timeFunction = function(toTime) { return () => { console.time('ListFocus'); var result = toTime.call(this,...Array.from(arguments)); console.timeEnd('ListFocus'); return result; }; }; isHidden(domElement) { if(!domElement) {return true; } return domElement.offsetWidth <= 0 && domElement.offsetWidth <= 0 || domElement.getAttribute('aria-hidden') === "true"; }
class ParseFocusable { constructor({domElement, filter=isFocusable, timeFocus=false}) { this.domElement = domElement; this.isFocusable = filter; this.focusArray = timeFunction.bind(this)(this.focusArray); } *focii(domElement, ignoreSelf) { var isHidden = isHidden(domElement); if(!ignoreSelf && this.isFocusable(domElement) && !isHidden) { yield domElement } if(!isHidden) {//if not hidden traverse yield *this.focii(domElement.firstElementChild) } if(!ignoreSelf){//if not initial object, get siblings yield *this.focii(domElement.nextElementSibling); } } focusArray() { return [for(n of this.focii(this.domElement,true)) n]; } } console.clear(); var allElements = new ParseFocusable({domElement:document.body,timeFocus:true}).focusArray(); console.log(allElements);
var sliding = function *(arr, numFields) { if(numFields <= 0) { numFields = 1; } var idx=0; while(idx + numFields < arr.length) { yield arr.slice(idx,idx+numFields); idx+=1; } }; console.clear(); console.log( [for (x of sliding([1,2,3,4],2)) x]); //[1,2][2,3][3,4]
class ParseFocusable { constructor() { this.forward = new WeakMap(); this.reverse = new WeakMap(); } buildTabOrder() { for(var [a,b] of sliding(this.focusArray())) { this.forward.set(a,b); this.reverse.set(b,a); } } next(domElement) { this.forward.get(domElement); } previous(domElement) { this.reverse.get(domElement); } }
class HttpResolver { //class constructor({url, method, data}) { this._xmlHttpRequest = new XMLHttpRequest(); this._promise = new Promise(this.resolve.bind(this)); //context is important here es5 this._xmlHttpRequest.open(method, url); this._xmlHttpRequest.send(data); } getData() { return this._xmlHttpRequest.responseText; } resolve(resolve,reject) { this._xmlHttpRequest.onreadystatechange = () => { if(this._xmlHttpRequest.readyState==4 && this._xmlHttpRequest.status==200) { resolve(this.getData()); } } this._xmlHttpRequest.ontimeout = () => { throw new Error('timeout'); } } get promise() { return this._promise; } //get modifier (Use .promise instead of .promise() es5 }
class JSONResolver extends HttpResolver { //extends getData() { return JSON.parse(super.getData()); } } var url = 'http://taginfo.openstreetmap.org/api/4/search/by_keyword?query=fire&page=1&rp=10', method = 'get'; //thanks to openstreetmap for the easily accessible cors api. var act = new HttpResolver({url, method}); var act2 = new JSONResolver({url, method}); act.promise.then((data) => console.log(typeof data)); act2.promise.then((data) => console.log(typeof data));
//Lexer.js export {Lexer}; //valid, Lexer is an export import {Lexer} from 'Lexer'; //valid, 'Lexer' has an export. //Lexer.Lexer is available module Lexer from 'Lexer'; //same as line above. only one will win import * as Lexer from 'Lexer' ; //invalid, because of no default import Lexer from 'Lexer';
//tokenClasses.js export var NEWLINE = new RegExp(/(\n+)/); export var SPACE = new RegExp(/([^\n][\s\t]+)/); export var WORD = new RegExp(/(\w+)/); export var PUNCT = new RegExp(/([\^\[\]\!\*\+\-`#])/); //import without any var request gets everything export default {SPACE, NEWLINE, WORD,PUNCT}; //main.js // war with {SPACE, NEWLINE, WORD,PUNCT}; import * as tokens from 'tokenClasses' module tokens from 'tokenClasses'; //works. there is a default import tokenDefault from 'tokenClasses'; //works import {SPACE} from 'tokenClasses';
var wm = new WeakMap(); var m = new Map(); var s = new Set(); (function() { var c = {'not':'me'}; m.set(c,{'o':'k'}); wm.set(c,{'o':'k'}); s.set(c); console.log(wm.get(c)); } )() wm.has(m.keys().next().value); s.has(m.keys().next().value); m = undefined; s = undefined; //after next gc wm.size (if it existed) would be 0 //ES6 Spec..an ECMAScript implementation must not provide any means to observe a key of a //WeakMap that does not require the observer to present the observed key.Hey you. Go line by line. Make sure to go into how yield pauses execution until the next time data is needed.
var title = 'El presidente'; var name = 'Walter'; var short = {title,name}; var long = {title:title, name:name}
type: "ObjectExpression", properties: [ { type: "Property", key: { type: "Identifier", name: "title", loc: null }, value: { type: "Identifier", name: "title", loc: null }, kind: "init", method: false, shorthand: true } }, { type: "Property", key: { type: "Identifier", name: "name", loc: null }, value: { type: "Identifier", name: "name", loc: null }, kind: "init", method: false, shorthand: true } } ]
"init": { "type": "ObjectExpression", "properties": [ { "type": "Property", "key": { "type": "Identifier", "name": "title" }, "value": { "type": "Identifier", "name": "title" }, "kind": "init" }, { "type": "Property", "key": { "type": "Identifier", "name": "name" }, "value": { "type": "Identifier", "name": "name" }, "kind": "init" } ] }
var Shorthand = Visitor.extend( { visitObjectExpression: function(objectExpression) { var newProperties = objectExpression.properties.map(function(prop) { return b.property( prop.kind, prop.key, this.visit(prop.value), prop.method, false);//is shorthand }.bind(this)); return b.objectExpression(newProperties); } }); new Shorthand().visit(ast); var output = recast.print(ast).code;
//arrow + destructuring + default params var fibNext=({last=0,current})=>{ return last + current}; var gen = function *(...two ) { //generator + rest params var [last,current] = two; //destructuring var next = fibNext({last,current}); //shorthand object syntax while(next < 1000) { next = fibNext({last,current}); [last, current] = [current,next]; //destructuring yield next; //yield keyword (for generators) } } for(let z of gen(0,1)) { //generator + let var q = [ for (n of gen(...[0,1])) if (n=== z) n ] //iterators + array comprehension + spread operator console.log(`Runtime complexity ${q}`); //string templating } export gen //modulesTest
class Parent { constructor(eek) { this.eek = eek; } height(h) { if(h) { this.h =h;} else { return this.h; } } }
class Child extends Parent { constructor() { super(10); } height(h) { super.height(h); this.h2=h; } static defaultKid() { var toBe = new Child(); toBe.height(32); toBe.name = 'Shakespeare'; return toBe; } }