JS Dev
June 2015
Browsers eagerly implemented stuff
Traceur
6to5
Generate a sequence, one item at a time
1 1 2 3 5 8
F
2
D
A
Z
U
C
3
1
8
3
9
1
More general: Function that can be paused in the middle
Star: indicates a generator function
function *foo() {
// ...
yield "bar1";
// ...
yield "bar2";
// ...
}
Yield: pauses the function
function *foo() {
console.log("running");
}
foo();
Nothing happens!
var generator = foo();
// generator = { next: function() { ... }, throw: function() { ... }};
function *foo() {
console.log("running");
var x = yield 1;
var y = yield 2;
return 3;
}
var generator = foo();
var result1 = generator.next();
// console: "running"
// result1 = {value: 1, done: false}
var result2 = generator.next();
// result2 = {value: 2, done: false}
var result3 = generator.next();
// result3 = {value: 3, done: true}
function *foo() {
var x = yield 1;
var y = yield 2;
return x + y;
}
var generator = foo();
var result1 = generator.next();
// result1 = {value: 1, done: false}
var result2 = generator.next(10);
// result2 = {value: 2, done: false}
var result3 = generator.next(20);
// result3 = {value: 30, done: true}
function *range(start, end) {
while (start != end) {
yield start;
start++;
}
}
for (let i of range(0, 10)) {
console.log(i);
}
> 0
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
function *fibonacci() {
var prev = 0, cur = 1;
while (true) {
let sum = cur + prev;
yield sum;
prev = cur
cur = sum
}
}
for (let n of fibonacci()) {
if (n > 1000)
break;
console.log(n);
}
> 0
> 1
> 1
> 2
> 3
> 5
> 8
...
26 | 39 | n/a | 26 | n/a |
Released 14 months ago | Released 3 months ago | Released 2 months ago |
function Animal() {
this.cuteness = 0; // neutral
this.hunger = 100; // 0: has no hunger, 100: needs food
this.approach = function() { } // do nothing
// Getters
Object.defineProperty(this, "fullness", {
get: function() {
return 100 - this.hunger;
}
});
}
Animal.prototype.feed = function(type) {
this.hunger--;
}
Animal.talk = function(animal1, animal2) {
// when animals are same species chitchat else growl
}
var unknownSpecies = new Animal();
Why can't we use classes. I know classes.
What is this?
class Animal() {
constructor() {
this.cuteness = 0; // neutral
this.hunger = 100; // 0: has no hunger, 100: needs food
}
approach() {
// do nothing
}
get fullness() {
return 100 - this.hunger;
}
feed(type) {
this.hunger--;
}
static talk(animal1, animal2) {
// when animals are same species chitchat else growl
}
}
A minimal class proposal
class Cat extends Animal {
constructor() {
super();
}
approach() {
this.runAway()
}
feed(type) {
if (isDelicious(type))
super.feed(type)
// Cats are picky even when hungry.
}
}
No multiple inheritance!
n/a | n/a | n/a | n/a | n/a |
Available in "Technical Preview" using "Experimental Web Platform Features" |
Traceur | 6to5 |
function Archer() {
this.arrows = 100;
setInterval(function shoot() {
this.arrows--;
}, 5 * 1000);
}
var a1 = new Archer();
function Archer() {
var self = this;
this.arrows = 100;
setInterval(function shoot() {
self.arrows--;
}, 5 * 1000);
}
var a1 = new Archer();
function Archer() {
this.arrows = 100;
setInterval(function shoot() {
this.arrows--;
}.bind(this), 5 * 1000);
}
var a1 = new Archer();
function Archer() {
this.arrows = 100;
setInterval(() => {
this.arrows--;
}, 5 * 1000);
}
var a1 = new Archer();
Shorter syntax
Lexically binds |this|
([param] [, param]) => {
statements
}
param => expression
// 1. Basic
(x, y) => {
return x+y
}
// 2. No return needed (for single expressions)
(x, y) => x+y
// 3. No parentheses (for one argument)
x => Math.pow(x, 2);
// 4. Or
x => {
return Math.pow(x, 2);
}
// 5. No arguments
() => Math.random()
23 | n/a | n/a | n/a | n/a |
Released one and a half year ago | Available in "Technical Preview" using "Experimental Web Platform Features" |
Assign data from Array or Object to variables
var [a, b] = [1, 2];
// a = 1, b = 2
var [a, ,b] = [1,2,3];
// a = 1, b = 3
var [a, b, ...c] = [1, 2, 3, 4, 5];
// a = 1, b = 2, c = [3, 4, 5]
var [b, a] = [a, b]
// swaps the content of a and b
var { data : var1 } = { data : 50 }
// var1 = 50
var { m: month, y: year } = { d: 1, m: 2, y: 2015}
// month = 2, year = 2015
var { child: { data: element } } = { child : { child: null, data: 1}, data: null }
// element = 1;
var { data : data } = { data : 50 }
var { data } = { data : 50 }
// data = 50
var { rhs, lhs, data } = { rhs : {}, lhs: {}, data: 50 }
// rhs = {}, lhs = {}, data = 50
function g({name: x}) {
console.log(x);
}
g({name: 5, foo: 0})
// Console: 5
// Fail-soft destructuring
var [a] = [];
a === undefined;
// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;
Not implemented yet!
34 | n/a | n/a | n/a | 7.1 |
Released 2 months ago | Released 5 monts ago |
Fix dependencies of Libraries
Using the 'script'-tag is not scalable
CommonJS Modules
Asynchronous Module Definition (AMD)
/* ------ lib.js ------ */
var privateProperty = 1;
export var publicProperty = 2
function privateFunction() { /* ... */ }
export function publicFunction() { /* ... */ }
export default function () { /* */ }
/* ------ main.js ------ */
import { publicProperty, publicFunction } from 'lib';
// publicProperty = 2, publicFunction = function () { /* ... */ }
import { publicFunction as libfunc } from 'lib';
// libfunc = function() { /* ... */ }
import { default as foo } from 'lib';
import foo from 'lib';
// foo now contains the default function
import * as mylib from 'lib';
// mylib = { publicProperty: 2, publicFunction: function() { /* ... */}}
System.import('some_module')
// Returns a promise? that loads the module async
To be determined
Make it possible to load libraries sync and async
Abstraction for Async code
JS executes sequentially and blocks all other execution
Easiest to reason about
while (true) {
// Crunch some data.
}
// Make sure first image is loaded
var img = document.getElementsByTagName("img")[0]
while (!img.complete) {
// not yet completed
}
// Completed, now we can do something with it.
So we need async behaviour.
Enter events and continuation functions
// Make sure first image is loaded
var img = document.getElementsByTagName("img")[0]
img.onload = function() {
// Completed, now we can do something with it.
}
What if img was already loaded?
Just add some more code. DUH!
if (img.completed) {
img.onload();// Make sure first image is loaded
}
the idea is to make this simpler with promises and have some nice tools around it.
function executor(resolve, reject) {
/* do something */
if (/* fail */)
reject(); // Bonus, will also get called upon Error.
/* done */
resolve();
}
var promise = new Promise(executor);
promise.then(function() {
/* Let's do something with the result. */
}, function() {
/* Failed. */
})
var img = document.getElementsByTagName("img")[0]
ready = img.getReadyPromise() // imagine this exists.
ready.then(function() {
// Completed, now we can do something with it.
})
var imgs = document.getElementsByTagName("img")
ready = imgs[0].getReadyPromise() // imagine this exists.
ready.then(function() {
return imgs[1].getReadyPromise(); // return promise.
}).then(function() {
// both images are loaded.
});
var imgs = document.getElementsByTagName("img")
var promises = [ imgs[0].getReadyPromise(), imgs[1].getReadyPromise() ]
Promise.all(promises).then(function() {
// Both images are loaded.
})
29 | 32 | n/a | 19 | 7.1 |
Released 9 months ago | Released 1 year ago | Available in "Technical Preview" using "Experimental Web Platform Features" | Released 1 year ago | Released 5 monts ago |
Might be present in ES7, or even later.
Very experimental features (implemented in Nightly).
Instable APIs.
Use at your own risks!
Add a way to describe data structures which members have defined types.
Types among {u,}int{8,16,32,64} / float{32,64} / String / Object, etc..
var {StructType, ArrayType} = TypedObject;
// Create a simple type
var Pixel = new StructType({'r': uint8, 'g': uint8, 'b': uint8});
// Create an array type
var Square = new ArrayType(Pixel, 4);
// Compose types!
var Image = new StructType({'id': uint16, 'src': Square});
var p = new Pixel({r: 128, g: 42, b: 25});
p.g; // shows 42
// Omit a field in the constructor to give it a default value
var p2 = new Pixel({r: 128, b: 56});
p2.g; // shows 0
// Arguments are coerced to fit the specified type
var p3 = new Pixel({r: 128, g: 35, b: 1337});
p2.b; // shows 57
// Let's instantiate an ArrayType
var sq = new Square([
{r: 24, g: 35, b: 46},
{r: 52, g: 63, b: 74},
p,
p2
]);
// You can't add attributes to Typed objects instances
var p = new Pixel();
p.id = "let's sneak in a string, i'm sure the VM won't see it";
// TypeError: Pixel is not extensible
// Typed objects are objects (!)
typeof p2; // "object"
var p2 = new Pixel();
p == p2; // false
p === p2; // false
If we can prove an object has a stable shape ("hidden class") and we know its definite properties, we can handle it as a Typed Object.
function PixelFactory(r, g, b) {
this.r = r | 0; // Forces int32 coercion
this.g = g | 0;
this.b = b | 0;
}
var Pixel = new StructType({r: int32, g: int32, b: int32});
// What if we handle an object created from the PixelFactory as a
// Typed Object with the Pixel type?
Use vector operations directly in JavaScript and have these jitted as vector processor instructions.
A normal operation takes two input operands.
A SIMD operation operates on pairs of input operands.
Implementations of SIMD: SSE (x86), NEON (arm)
This is fast! Mostly used in heavily parallel processing (audio / image processing, codecs, games...).
Fixed-length: 128 bits (much useful, well supported, very SIMD, wow).
Uniform behaviours of operation accross platforms.
New value types: int8x16, int16x8, int32x4, float32x4, float64x2.
These can be embedded in Typed Objects descriptors.
function fibonacci4(n) {
var x = SIMD.int32x4(1, 1, 2, 3);
var y = SIMD.int32x4(1, 2, 3, 5);
while (n--) {
var tmp = y;
y = SIMD.int32x4.add(x, y);
x = tmp;
}
return x;
}
var v = fibonacci4(10);
console.log(v.x, v.y, v.z, v.w); // (89, 144, 233, 377)
var x = SIMD.float32x4(1, 2, 3, 4);
var y = SIMD.float32x4(1, 2, 3, 4);
var previous = SIMD.float32x4.splat(0); // copies the value in all four lanes
var threshold = SIMD.float32x4.splat(.001337);
while (true) {
previous = x;
x = SIMD.float32x4.add(x, y);
x = SIMD.float32x4.sqrt(x); // square root
let v = SIMD.float32x4.sub(x, previous); // subtract
v = SIMD.float32x4.abs(v); // absolute
let cmp = SIMD.float32x4.lessThanOrEqual(v, threshold); // <=
if (cmp.signMask == 0b1111) // true in all lanes
break;
};
console.log(x.x, x.y, x.z, x.w);