More Related Content Similar to JavaScript (ECMAScript) 2013 (20) JavaScript (ECMAScript) 20131. Draft
Ecma/TC39/2013/0xx
ECMA-262
6th Edition / Draft November 8, 2013
Draft
ECMAScript Language
Specification
JavaScript 2013
Report Errors and Issues at: https://bugs.ecmascript.org
Product: Draft for 6th Edition
Component: choose an appropriate one
Version: Rev 21, November 8, 2013 Draft
ECMAScript 6th & JavaScript Fast Parts
@HTML5 Conference 2013
by Tomoya Asai (dynamis)
Reference number
ECMA-123:2009
© Ecma International 2009
Last Update: 2013/12/11
13. JavaScript 改良への動き
2008 ECMAScript 4th 終了
Yahoo! & MS の反対で挫折
ECMAScript Harmony へ
次世代 ECMAScript コードネーム
2009.12 ECMAScript 5th
小さな変更だけの ES3.1 ベース
2013? ECMAScript 6th
遂に抜本的な改定の時が来た!
ECMAScript の標準化は TC39 の 2 ヶ月に1度のミーティングと ML で議論
14. ECMAScript 6th の目標
より開発しやすい言語
想定用途: 複雑なアプリ、ライブラ
リ、機械生成コードの実行環境
テスト可能な仕様
相互運用性を確保
バージョニングは単純に
静的検証も可能に
実行よりコンパイル時にエラー検出
http://wiki.ecmascript.org/doku.php?id=harmony:harmony
19. ECMAScript 5th にコンパイル
Traceur Compiler
ES Harmony からのコンパイル用
https://github.com/google/traceurcompiler
TypeScript
ES Harmony の一部+独自拡張
http://typescriptlang.org/
たまに紹介されてる Harmonizr や Six は開発終了したっぽい
21. Shim (Polyfill) で拡張
新しい API や型の一部はプロ
トタイプ拡張で対応できる
この方式では構文変化は対応不可
es6-shim
https://github.com/paulmillr/es6-shim
ECMAScript-6
https://github.com/monolithed/
ECMAScript-6
24. 分割代入 (Destructuring)
// 配列で受け取るサンプル:
// 値の入れ替え
[a, b] = [b, a];
!
// 関数から複数の値を返して一気に変数に代入
var [c,d] = (function f() { return [1,2]; })();
// -> c=1, d=2
!
// 一部省略や入れ子も可能
var [e,,[x,y]] = (function f(){
return [3,4,[10,20]]
})();
// -> e=3,x=10,y=20
http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
25. 分割代入 (Destructuring)
// オブジェクトで受け取るサンプル
var fx={ name:"Firefox", vendor:"Mozilla", ver:26 };
var ch={ name:"Chrome", vendor:"Google", ver:31 };
var browsers={ firefox: fx, chrome: ch };
!
// 欲しいプロパティだけ一括代入
var { name: n, ver: v } = fx;
// -> n="Firefox", v=26
!
// 関数の引数から必要なプロパティだけ受け取る
(function ({ vendor: ven }) {
console.log(ven);
})(fx); // -> "Mozilla"
http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
26. 未実装や議論中の構文例
// 最終的にどうなるか分かってません m(_ _)m
!
// default value
let { foo = 10, bar = 5 } = { foo: 12 };
console.log(foo); // 12
console.log(bar); // 5
!
// 関数の引数での rest element
function foo([x, ...xs]) {}
http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
27. default & rest parameter
モダンな言語では当然の機能
だが Firefox 以外は未サポート
default parameter
引数のデフォルト値を設定
rest parameter
残りの引数を配列で受け取る
28. default parameter
e = document.body; // 何か適当な要素
function setBackgroundColor(element,
color='orange') {
element.style.backgroundColor = color;
}
setBackgroundColor(e); // オレンジに
setBackgroundColor(e, 'blue'); // 青に
setBackgroundColor(e, undefined); // オレンジに
!
// デフォルト値は呼び出し毎に生成される
// 同一オブジェクトが渡される Python などとは違う
function getObject(o={}) { return o; }
getObject() == getObject() // -> false
http://wiki.ecmascript.org/doku.php?id=harmony:parameter_default_values
29. rest parameter
function f(a, b, ...args) { return args; }
f("IE", "Chrome"); // -> []
f("IE", "Chrome", "Firefox"); // -> ["Firefox"]
!
// rest arguments は Array のメソッドが使える
// [].slice.call(arguments) ハックとか不要に
function sortRestArgs(...args) {
var sortedArgs = args.sort();
return sortedArgs;
}
http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters
30. !
配列の内包表記 (Comprehensions)
配列の内包表記
Python や Haskell にもあるやつ
最近構文変わったので注意!
Firefox 2 12 は JS1.7 の構文
Firefox 13 は旧 ES6 仕様
2013.01 に変更された (RTL→LTR)
最新 ES6 構文の実装はまだない
http://wiki.ecmascript.org/doku.php?id=harmony:array_comprehensions
31. 配列の内包表記 (Comprehensions)
// 配列のフィルタとマップ
[for (x of [1,-4,5,3,-7]) if (x > 0) x] // -> [1, 5, 3]
// ES5 なら次のように書く
// [1,-4,5,3,-7].filter(function(x) { return x > 0 });
[for (x of [2,4,6]) x*x] // -> [4, 16, 36]
// ES5 なら次のように書く:
// [2,4,6].map(function (x) { return x*xi });
!
// 配列のデカルト積やラベル生成もシンプルに
[for (i of [0,2,4]) for (j of [5,3]) i*j]
// -> [0, 0, 10, 6, 20, 12]
[for (x of 'abc'.split(''))
for (y of '123'.split('')) (x+y)];
// -> ["a1","a2","a3","b1","b2","b3","c1","c2","c3"]
32. 配列の内包表記の構文変更
// 旧 ES6 構文 (現行 Firefox の実装)
// 値の定義が最初 (for や if の左)
return [a+b for (a of A) for (b of B) if (a > b)]
!
// 新 ES6 構文
// 値の定義は最後 (for や if の右)
return [for (a of A) for (b of B) if (a > b) a+b]
!
// 新構文の方が読みやすいので構文変更された
https://gist.github.com/dherman/b250d1fad15dbb5f77a5
35. let
{
// let 定義: ブロックスコープ
let a = 1, b = 10;
// let 式・文: let (...) に続く式・文中だけで有効
let (a = 100, c = 300) console.log(a); // -> 100
// for 文などでの let
for (let a=0; a<3; a++) {
console.log(a+b); // -> 10, 11, 12
}
console.log(a); // -> 1
}
console.log(a); // × ReferenceError: a is not
// defined
36. const
// 不変定数を定義
const browser = "Firefox";
!
// 再定義は TypeError となる
const browser = "Internet Explorer";
// TypeError: redeclaration of const browser
!
// 定数への代入は単に無視される
browser = "Chrome";
console.log(browser); // -> "Firefox"
38. Class の利用例
// クラスベース OOP でよく見る感じ
class Animal {
constructor(name) {
this.name = name;
this.hungry = true;
}
eat() {
this.hungry = false;
}
run() {
this.hungry = trye;
}
}
39. Class - extends
// 派生クラスの定義がシンプル
class LesserPanda extends Animal {
constructor(name, tail) {
super(name);
this.tail = tail;
}
}
40. 参考: EcmaScript 5th の場合
// プロトタイプベース
function Animal(name) {
this.name = name;
this.hungry = true;
}
Animal.prototype.eat = function() {
this.hungry = false;
}
Animal.prototype.run = function() {
this.hungry = true;
}
41. 参考: ECMAScript 5th で派生
// プロトタイプベースでの派生は少し気持ち悪い
function LesserPanda(name, tail) {
Animal.call(this, name);
this.tail = tail;
}
LesserPanda.prototype
= Object.create(Animal.prototype);
LesserPanda.prototype.constructor = LesserPanda;
43. Module
module 'math' {
export function sum(x, y) {
return x + y;
}
export var hbar = 1.054571726e-34; // ディラック定数
}
import {sum, hbar} from 'math';
alert("2 = " + sum(hbar, hbar));
// オブジェクトのプロパティに読み込み
module Math from 'math';
alert("2 = " + Math.sum(Math.hbar, Math.hbar));
44. module import いろいろ
// module のデフォルト export を読み込み
import $ from "jquery";
// 変数のプロパティに読み込み
module crypto from "crypto";
// 変数に読み込み
import { encrypt, decrypt } from "crypto";
// 別名で読み込み
import { encrypt as enc } from "crypto";
// 他のモジュールを読み込んで再 export
export * from "crypto";
// 他のモジュールから一部だけ再 export
export { foo, bar } from "crypto";
http://wiki.ecmascript.org/doku.php?id=harmony:modules
47. Arrow Function
// return するだけのコールバックがシンプルに
[1,2,3].map(x => x * x);
// ES5 ではこう書く必要があった:
// [1,2,3].map(function (x) { return x * x; });
!
// 引数が 1 つ以外の場合は引数を () で括る
setInterval(() => {
alert("HEY! 提督ぅー!alertしてもイイけどサー、時間
と場所をわきまえなヨー!");
}, Math.random()*10*1000);
!
// n! (nの階乗) を求める関数もシンプルに
var factorial=((f=n=>n>1 ?n*f(n-1):1)=>(f))();
factorial(10); // 3628800
http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax
48. Arrow Function における this
// this は矢印関数を囲むスコープのものにバインド
// コールバック利用時に self=this とか不要になる
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // this は Person オブジェクト
}, 1000);
}
var p = new Person();
!
// 注: strict mode でも this はレキシカルに bind
// 済みとして振る舞うので undefined にならない
https://developer.mozilla.org/docs/Web/JavaScript/Reference/arrow_functions
50. Generator 用語
イテレータ (iterator)
{value, done} を返す next メソッドを
持つオブジェクト
ジェネレータ (generator)
ジェネレータ関数で挙動を定義・生
成されているイテレータ
ジェネレータ関数
ジェネレータを生成する特殊な関数
yield で next で返す value を指定
http://domenic.me/2013/09/06/es6-iterators-generators-and-iterables/
51. Generator を使ったループ処理
// ジェネレータ関数 (ジェネレータのコンストラクタ)
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
[prev, curr] = [curr, prev + curr];
yield curr; // 値を返して一時停止
}
}
for (n of fibonacci()) {
if (n > 20)
break;
console.log(n); // 順に 1, 2, 3, 5, 8, 13
}
52. Iterator としての Generator
function* counterGenerator() {
let c = 0;
for (;;) {
yield c++; // 値を返して一時停止
}
}
// ジェネレータを生成
let counter = counterGenerator();
// next() メソッドで {value, done} を得る
counter.next(); // -> {value: 0, done: false}
counter.next(); // -> {value: 2, done: false}
counter.next().value; // -> 2
counter.next().value; // -> 3
補足: Generator を複数生成したらそれぞれ独立してカウントできます
54. Promise で非同期処理
let p = new Promise(function (resolve, reject) {
// 3 秒後に resolve 呼んでプロミスが解決する
setTimeout(resolve, 3000);
});
!
// 解決した (resolve が呼ばれた) ときに実行:
p.then(function () {
alert('3 秒たったよ!');
}).then(function () {
// 解決済みなので即ここも実行される
alert('既に 3 秒過ぎてるよ!');
});
詳しい日本語解説: http://js-next.hatenablog.com/entry/2013/11/28/093230
55. Promise で引数を使う
let p = new Promise(function (resolve, reject) {
// 60 秒後にこのプロミスは解決する
// resolve の引数に "60 秒!" を渡す
setTimeout(resolve, 60*1000, "60 秒!");
});
!
// resolve の引数を受け取って使う
p.then(function (message) {
alert(message); // -> "60 秒!" と表示される
})
56. Promise でエラーハンドリング
p = new Promise(function (resolve, reject) {
dream(); // 未定義の関数を呼ぶ (エラー発生)
})
!
// エラー発生時は then をスキップして catch へ
p.then(function (message) {
// p は解決しないのでこのブロックは実行されない
alert(message);
}).catch(function (error) {
// p でエラーが発生するのでこのブロックを実行
alert(error);
// -> ReferenceError: dream is not defined
});
57. Promise のチェイン
// s 秒後に解決して resolve に s を渡す Promise を作って返す関数
function wait(s) {
var p = new Promise(function (resolve) {
setTimeout(resolve, s*1000, s)
});
return p; // Promise を返す
}
// ログを吐いてから s を返す
function log(s) {
console.log("さっきから "+s+" 秒過ぎたよ")
return s; // then で呼ばれたときは Promise にキャストされる
}
// wait 呼ぶ度に未解決の新しい Promise ができる
// 5 秒ごとに 3 回 log が呼ばれる
wait(5).then(log).then(wait)
.then(log).then(wait)
.then(log);
58. XHR に Promise を使う
function ajax(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest
xhr.open('GET', url)
xhr.onload = function () {
if (xhr.status == 200) {
resolve(xhr.response); // 成功時に解決
} else {
reject(new Error(xhr.statusText)); // 404 などでリジェクト
}
}
xhr.onerror = reject; // その他のエラー
xhr.send();
})
}
function onsuccess(response) { alert("成功: "+response); }
function onerror(error) { alert("エラー: "+error); }
ajax(url).then(onsuccess).catch(onerror)
http://js-next.hatenablog.com/entry/2013/11/28/093230
60. Collections
Simple Set & Map
Python: set, dict
Ruby: Set, Hash
Java: java.util.HashSet,
java.util.HashMap
C++: std::unordered_set
std::unordered_map
WeakMap & WeakSet
弱参照バージョン (割愛)
62. Simple Map
var map = new Map();
var str = "Mozilla", obj = {}, func = function(){};
// Map に値を格納
map.set(str, "Firefox");
map.set(obj, "Thunderbird");
map.set(func, "Japan");
// キーに対応する値を取得
map.get(str); // -> "Firefox"
map.get(obj); // -> "Thunderbird"
map.get(func); // -> "Japan"
// 設定したキーと引数の比較は == ではないので注意
map.get("Mozilla"); // -> "Firefox"
map.get({}); // -> undefined
map.get(function(){}) // -> undefined
キーと引数の比較は === 演算子に近いが厳密には === とも異なる
63. API Improvement (割愛)
String の拡張
startsWith, endsWith, contains,
repeat, fromCodePoint ...
Number の拡張
isFinite, isNaN, isInteger...
Math の拡張
cosh, sinh, tanh, arosh, asinh,
atanh, log1p, log2, log10, sign ...
65. Note: JavaScript Good Parts
人間が誤認しにくいコード
意図せぬ挙動を防げる記法 (コー
ディング規約) を論理的に解説
Douglas Crockford 提唱
JSON の生みの親、JS 業界の重鎮
ECMAScript 4th を葬った人です
職業: The Boss of You
69. Typed Array
型固定配列で高速数値演算
元々 WebGL で導入され FileAPI,
XHR2, WebSocket などでも採用
分離して ECMA6th にも入った
IE9 非サポートに注意
shim はいろいろある
https://github.com/jDataView/jDataView
https://bitbucket.org/lindenlab/llsd/src/
default/js/typedarray.js
http://www.khronos.org/registry/typedarray/specs/latest/
71. Typed Array
// 16 バイト長のバッファを確保
var buffer = new ArrayBuffer(16);
// 32bit 整数 x 4 として読み出すビューを定義
var int32View = new Int32Array(buffer);
// 32bit 整数として 0, 2, 4, 6 を格納
for (var i=0; i<int32View.length; i+
+) { int32View[i]=i*2; }
// 16bit 整数 x 8 として同じバッファを読み出すビュー
var int16View = new Int16Array(buffer);
// 実際に読み出してみる
for (var i=0; i<int16View.length; i++) {
console.log(int16View[i]);
}
// -> 0, 0, 2, 0, 4, 0, 6, 0
https://developer.mozilla.org/docs/Web/JavaScript/Typed_arrays
73. asm.js とは
JavaScript のサブセット仕様
既存 JavaScript エンジンで動作
高度に最適化可能なパターン
静的型で事前コンパイル可能
経験的に JIT する必要が無い形式
全体または関数単位で有効化
"use asm" とファイルまたは関数
の冒頭に記載する
"Fast Parts" (の更に一部) を明文化・定義したもの http://asmjs.org/
75. asm.js がもたらすもの
Web を Native の速度に
CrankShaft や IonMonkey の SSA 最
適化 JIT の効果を確実かつオーバー
ヘッドなく使えるように
予測可能なパフォーマンス
暗黙知 (ダーティハック) にお別れ
ams.js 形式で書けば必ず十分に高
速化されることが保証される
予測不能な JIT/GC を回避
"Fast Parts" である ams.js なら確実に速く http://asmjs.org/
77. C 言語に迫る高速化 (asm.js)
asm.js 導入直後で既に C の 2 倍遅い程度まで
(Java や C# の処理速度と同程度以上の水準に)
2013/03 - http://kripken.github.io/mloc_emscripten_talk/#/19
78. C 言語に迫る高速化 (asm.js)
asm.js 形式の JavaScript コード実行速度は
C 言語より数割遅い程度まで迫りまだ高速化中
2013/09 - http://kripken.github.io/mloc_emscripten_talk/sloop.html#/7
79. 実レベル: Box2D 物理演算エンジン
Box2D では C 言語の 2 倍遅い程度の速度
!
Chrome や IE でも通常の JS より asm.js が高速
Box2DWeb のコードが悪いって話を差し引いても十分
!
Java や CrossBridge (Flash C++ Compiler) と同等以上
2013/07 - http://kripken.github.io/mloc_emscripten_talk/sloop.html#/8
80. 実用例: Unreal Engine 3
100 万行以上の C & OpenGL コードを 4 5 日で移植
LLVM + Emscripten で JavaScript (asm.js) に変換
epic CITADEL http://www.unrealengine.com/html5/
82. asm.js にまつわる誤解
機械生成なんてナンセンス
!?
CoffeeScript や TypeScript どころ
か 2006 年には GWT 出てる
特定パターンだけ高速は反則
ベンチを中心に特定パターンへの
最適化が積み重ねられてます
Emscripten などの機械生成コード
利用も広がっておりいずれにして
も最適化対象となるパターン
http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html
83. asm.js にまつわる誤解
x = x¦0 とか非対応だと重い
!?
既存エンジンが既に最適化していた
パターン (SunSpider crypto 等)
高速実行可能なコード生成を行っ
ていたツールからできた規則
特殊な JIT エンジンが必要
既存エンジンの簡単な拡張
Firefox では 3 人月、Chrome も
数ヶ月で最適化対応を進めた
http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html
84. asm.js にまつわる誤解
asm.js は新しい技術
!?
高速コード生成対象パターン
既存の最適化 JIT (CrankShaft や
IonMonkey) でコンパイルされる
asm.js は新しい仕様
JavaScript のサブセット
固定型は TypedArray で定義済み
Emscripten 実行速度は Mozilla だけ
有利とならず透明性を高めるため
http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html
85. asm.js にまつわる誤解
"use asm" での AOT は反則
!?
型の変わらないコードに対しては元々
原理的には AOT 可能 (だが大変)
機械生成で AOT 可能と保証できる
なら経験則で判別する必要ない
ES6 の Math.imul に依存してる
32bit 整数演算を行う関数 (後述)
影響は限定的だし Polyfill あります
asm.js 専用で生まれた訳じゃない
http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html
86. asm.js にまつわる誤解
PNaCl との一騎打ち
!?
C++ で書いたコードを高速に
Web で動かすという目的は一緒
HTML5 同様に既存 JS との互換性
を重視したアプローチが asm.js
PNaCl の成否に依らず JS の一部
である asm.js への最適化は続く
http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html
87. 参考: C to JS コンパイラ比較
Emscripten
Mandreel
Duetto
ライセンス
OSS
プロプラ
一部プロプラ
アーキテクチャ
LLVM IR
LLVM tblgen
LLVM IR
メモリモデル
TypedArray
TypedArray
JS Object
C/C++ 互換性
フル
フル
部分的
TypedArray
JS ネイティブ
関数呼び出し JS ネイティブ
をスタックに
API
その他
C (SDL etc)
Mozilla 製
カスタム
HTML5 ベース
JS 以外にも
Server-Clients
変換可能
http://mozakai.blogspot.co.uk/2013/11/c-to-javascript-emscripten-mandreel-and.html
89. asm.js がまだ C より遅い理由
コンパイルタイム
避けられないオーバーヘッド
別スレッドで AOT したりキャッ
シュしたりして解決していく
単精度演算ができない
元々 JavaScript は倍精度のみ
SIMD 命令が使えない
4 データ同時処理で 300% 高速化
91. Math.fround で単精度演算
// 精度によって結果は異なる
(1024+0.0001)+1024 // 単精度では 2048
!
// 単精度演算と結果が異なる可能性があるので
// 一旦倍精度に変換・演算してから単精度に変換
var f32 = new Float32Array(1000);
for (var i = 0; i < 1000; ++i)
f32[i] = (f32[i] + f32[i+1]) + 1;
!
// Math.fround で明示されれば単精度で実行
var f32 = new Float32Array(1000);
for (var i = 0; i < 1000; ++i)
f32[i] = Math.fround(f32[i] + f32[i+1]) + 1;
https://blog.mozilla.org/javascript/2013/11/07/efficient-float32-arithmetic-in-
93. Math.fround による高速化
Desktop (x86)
Nexus 10
Nexus 4
Galaxy S3
60%
45%
30%
15%
0%
Matrix Inversions
Matrix Graphics
Exponential
Fast Fourier Transfrom
Math.fround の導入によって数値演算
ライブラリの速度が最大 60% 高速化
https://blog.mozilla.org/javascript/2013/11/07/efficient-float32-arithmetic-in-javascript/
94. Math.imul
C 同様の 32bit 整数の掛け算
これも高速化を助ける関数
これを使わないとエンジンで常に
最適化できるとは限らない
https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
95. SIMD Module
128bit SIMD モジュール
TypedArray の拡張
対応データ型
float32x4, uint32x4
配列とビュー
Float32x4Array, Int32x4Array
既存 TypedArray のビューにも
Intel, Google, Mozilla が積極的に取り組んでいるところ
96. SIMD 命令が存在しないと遅い
複数データの並列同時計算
CPU 1 クロックで複数データ処理
同時に扱える数倍だけ速くなる
IA32/X64 の MMX/SSE など
ARMv7 の NEON など
CPU フル活用したいよね!
http://wiki.ecmascript.org/doku.php?id=strawman:simd_number
97. SIMD 命令の導入
// 4 つの数値を格納する TypedArray を宣言
var a = float32x4(1.0, 2.0, 3.0, 4.0);
var b = float32x4(5.0, 6.0, 7.0, 8.0);
!
// 型毎に決まった SIMD 命令で計算実行
var c = SIMD.float32x4.add(a,b);
// -> [6.0, 8.0, 10.0, 12.0]
// エンジンが最適化で SIMD 使う形に変換できない
// 場合に比べてこの計算は 4 倍 (300%) 高速化
https://github.com/johnmccutchan/ecmascript_simd