Standardization
"Things that are impossible just take longer." - Hixie
What was it like to hack JS in 10 days?
Me in 1993, before I created JavaScript in 10 days
1995, after I was done creating JS in 10 days
Java was the big Web VM
JavaScript was "little brother"
Think back to 1995... what was on TV then?
I had my big break that year...
I'd go to a real library to read Computer Science papers.
John Doerr claims that even an idiot could have been a successful VC in the 1980s:
"All you had to do was hang around Margaret Jacks Hall."
Java's bytecode design influenced my work on JS.
Java is typed (or statically typed) and has mostly-typed bytecode
JS is untyped (or dynamically typed)
So in 10 days in May 1995, I wrote
- A lexical scanner and parser for early JS
- The parser emitted stack-machine bytecode
- Which ran in a bytecode interpreter
Function.prototype.toString
bytecode decompiler
- The standard library was poor
Array
was Object
with .length
property
Date
hand-ported (h/t ksmith@netscape.com) from java.util.Date
Early DOM mattered as much as JS
class vector {
constructor(n) { this.arr = new Int32Array(n); }
sum() {
let la = this.arr;
let S = 0;
for (let i = la.length|0; (i=(i-1)|0) >= 0;)
S = (S + la[i|0])|0;
return S;
}
}
JS is untyped (dynamically typed), however:
asm.js is typed "bytecode" with deterministic performance
JS, a dynamically typed language, is often written with latent static types
Especially when "written" by compilers
Compiling to JS is not new
JS VMs compile to the metal
(just like Java but without declaring all types)
And the Java VM supports dynamic languages too:
The circle is now complete
Young Jackie Chan
Mature action hero
String.prototype.includes(txt, start)
let title = "JS Futures at ModernWeb.tw!";
title.includes("JS") title.includes("!") title.includes("XYZ") title.includes("JS", 3) https://github.com/tc39/Array.prototype.includes
String.prototype.startsWith(txt, start)
let title = "JS Futures at ModernWeb.tw!";
title.startsWith("JS") title.startsWith("js") title.startsWith("F") title.startsWith("F", 3)
String.prototype.endsWith(txt, end)
let title = "JS Futures at ModernWeb.tw!";
title.endsWith("!") title.endsWith(".tw!") title.endsWith("!", 3) title.endsWith("Fut", 6)
String.prototype.repeat(count)
console.log("x".repeat(3)) console.log("hello".repeat(2)) console.log("abc".repeat(4))
String.prototype.trim()
console.log(" x ".trim()) console.log(" \tx".trim()) console.log("foo bar\n".trim())
Template Strings
-
console.log(`In ES6, '\n' is a line feed`);
-
console.log(`In ES6, you can have multiline
strings`);
Template String Interpolation
var name = "Bob",
time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
Tagged Template Strings
function dedent(strings, ...values) {
let result = '';
for (let i = 0; i < strings.length; i++) {
result += strings[i].replace(/\n\s+/g, '\n') + values[i];
}
return result;
}
console.log(dedent `Hello ${name},
How are you ${time}?`);
Octal and Binary Literals
var mode = 0o755;
var bits = 0b101;
Number.isFinite
, Number.isNaN
console.log(isFinite("25")); console.log(Number.isFinite("25"));
console.log(isNaN("LOL")); console.log(Number.isNaN("LOL"));
Array.from(arraylike, mapfun)
let list = document.querySelectorAll('.speaker h2');
console.log(Array.from(list, elem => elem.innerHTML));
Destructuring (Array Pattern)
var m = 3, d = 15, y = 2015;
var [m, d, y] = [3, 15, 2015];
[m, d, y] = getDateTriple();
Destructuring (Object Pattern)
var today = {m: 3, d: 15, y: 2015};
var {m: month, d: day} = today;
console.log(month, day);
Object Literal Shorthand
function longhand(bar, baz) {
return {foo: true, bar: bar, baz: baz};
}
function shorthand(bar, baz) {
return {foo: true, bar, baz};
}
Block Scope
for (var i = 0; i < 3; i++) {
let j = i * i;
console.log(j); }
console.log(j);
Arrow Function Syntax
- Like CoffeeScript's "fat arrow"
- Outer
this
binding
- Not
new
-able
- No
arguments
object
- Always anonymous
Arrow Function: Expression Body
let square = x => x * x;
console.log(square(4));
let empty = () => undefined;
let add = (a, b) => a + b;
Arrow Function: Block Body
let Ackermann = (m, n) => {
if (m == 0) return n + 1;
if (n == 0) return Ackermann(m - 1, 1);
return Ackermann(m - 1, Ackermann(m, n - 1));
}
console.log(Ackermann(2,2)); console.log(Ackermann(3,3)); console.log(Ackermann(3,4));
Arrows: Great for Callbacks
Car.prototype.start = function () {
setTimeout(function () {
this.startDriving(); }, 1000);
};
Car.prototype.start = function () {
setTimeout(() => this.startDriving(), 1000);
};
Classes
class Animal {
constructor(name) {
this.name = name;
}
breathe() {
console.log(`${this.name} is breathing`);
}
}
Instead of The Prototypal Pattern
function Animal(name) {
this.name = name;
}
Animal.prototype.breathe = function() {
console.log(`${this.name} is breathing`);
}
Subclassing
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log(`Woof! ${this.name} is barking`);
}
}
Subclassing Further
class Bulldog extends Dog {
constructor(name) {
super(name);
}
breathe() {
super.breathe();
console.log(`${this.name} just drooled, too!`);
}
}
Simple Modules
let baz = 'baz';
export baz;
import {baz} from "baz.js";
Default Exports
export default function print(what) {
return `print module called with ${what}`;
}
import print from "print.js";
Mixing and Matching
import {baz} from "./baz.js";
console.log(`from module baz: ${baz}`);
let foo = 'foo';
export default foo;
export let bar = 'bar';
import {bar} from "foo.js";
ES6/2015, ES7/2016, ES8...
function chainAnimationsPromise(elem, animations) {
let ret = null;
let p = currentPromise;
for (let anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
});
}
return p.catch(e => { })
.then(() => { return ret; });
}
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for (let anim of animations) {
ret = yield anim(elem);
}
} catch(e) { }
return ret;
});
}
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for (let anim of animations) {
ret = await anim(elem);
}
} catch(e) { }
return ret;
}