"use strict";
で動かなくなる構文(with
文など)は避けるべき{[x]: a}
, {a, b}
, { f(x) { ... } }
)for (var x of xs)
)`${x} + ${y} = ${x + y}`
)[x, y] = xs
, {a, b} = obj
)let
) , 定数 (const
)(x, y) => { ... }
)class
, extends
, super
)function *
, yield
)Promise
function gcd(m, n) {
if (n === 0) {
return m;
} else {
return gcd(n, m % n);
}
}
function (x, y = 42)
)function (x, ...ys)
)f(...xs)
, [x, ...ys, z]
){[x]: a}
, {a, b}
, { f(x) { ... } }
)0b1010
, 0o755
)for (var x of xs)
)`${x} + ${y} = ${x + y}`
)/.../y
, /🍣🍺*🍖/u
)[x, y] = xs
, {a, b} = obj
)function myPow(x, y) {
if (typeof y === "undefined") y = 2;
return Math.pow(x, y);
}
console.log(myPow(3)); // 9
console.log(myPow(2, 10)); // 1024
function myPow(x, y) {
if (y === undefined) y = 2;
return Math.pow(x, y);
}
console.log(myPow(3)); // 9
console.log(myPow(2, 10)); // 1024
undefined
は immutable
undefined
という名前のローカル変数は定義できるfunction myPow(x, y = 2) {
return Math.pow(x, y);
}
console.log(myPow(3)); // 9
console.log(myPow(2, 10)); // 1024
function (x = 2, y)
はダメfunction f(x) {
console.log(x, Array.prototype.slice.call(arguments, 1));
}
f(2, 3, 5); // 2 [ 3, 5 ]
arguments
は Array
ではない
arguments
を Array
に変換するややこしいイディオムが存在するfunction f(x, ...ys) {
console.log(x, ys);
}
f(2, 3, 5); // 2 [ 3, 5 ]
Array.from(arguments)
で配列に変換することもできるfunction f(x, y, z) {
console.log(x + y * z);
}
f.apply(null, [2, 3, 5]); // 17
function f(x, y, z) {
console.log(x + y * z);
}
f(...[2, 3, 5]); // 17
var xs = [5, 7];
var ys = [2, 3].concat(xs, [11, 13])
console.log(ys); // [ 2, 3, 5, 7, 11, 13 ]
var xs = [5, 7];
var ys = [2, 3, ...xs, 11, 13];
console.log(ys); // [ 2, 3, 5, 7, 11, 13 ]
var key = "foo";
var obj = {};
obj[key] = "bar";
console.log(obj); // { "foo" : "bar" }
var key = "foo";
var obj = {[key]: "bar"};
console.log(obj); // { "foo" : "bar" }
var x = 2, y = 3, z = 5;
var obj = {x: x, y: y, z: z};
var x = 2, y = 3, z = 5;
var obj = {x, y, z};
var obj = {
f: function (x) {
console.log(x * this.y);
},
y: 42
};
var obj = {
f(x) {
console.log(x * this.y);
},
y: 42
};
for
– of
)var xs = [2, 3, 5];
for (var i in xs) {
console.log(xs[i]);
}
var xs = []; xs[5] = 42;
のようなパターンでアウトArray.prototype
を弄るわるいライブラリがいるとアウトfor
– of
)var xs = [2, 3, 5];
for (var i = 0; i < xs.length; ++i) {
console.log(xs[i]);
}
for
– of
)var xs = [2, 3, 5];
xs.forEach(function (x, i) {
console.log(x);
});
Array.prototype.forEach
を使う
for
– of
)var xs = [2, 3, 5];
for (var x of xs) {
console.log(x);
}
console.log(0b1010); // 10
console.log(0o755); // 493
b
/ o
は小文字でも大文字でも可var a = 7, b = 8;
console.log(a + " + " + b + " = " + (a + b));
var a = 7, b = 8;
console.log(`${a} + ${b} = ${a + b}`);
y
, u
)var re = /(\d+)\.?/y;
var ip = "127.0.0.1";
while (re.exec(ip)) console.log(re.lastIndex); // 4 6 8 9
lastIndex
から順次検索)console.log(/🍣🍺*🍖/.test("🍣🍺🍺🍺🍖")); // false
console.log(/🍣🍺*🍖/u.test("🍣🍺🍺🍺🍖")); // true
var xs = [2, 3, 5];
var x = xs[0], y = xs[1], z = xs[2];
var obj = {x: 2, y: 3, nested: {z: 5}};
var x = obj.x, y = obj.y, z = obj.nested.z;
var obj = {x: 2, y: 3, nested: {z: 5}};
var a = obj.x, b = obj.y, c = obj.nested.z;
var xs = [2, 3, 5];
var [x, y, z] = xs;
var obj = {x: 2, y: 3, nested: {z: 5}};
var {x, y, nested: {z}} = obj;
var obj = {x: 2, y: 3, nested: {z: 5}};
var {x: a, y: b, nested: {z: c}} = obj;
xs
, obj
が 1 回しか登場しないのが利点
let
)const
)let
)var s = "foo";
{
var s = "bar";
console.log(s); // bar
}
console.log(s); // bar
let
)var s = "foo";
(function () {
var s = "bar";
console.log(s); // bar
})();
console.log(s); // foo
let
)var s = "foo";
{
let s = "bar";
console.log(s); // bar
}
console.log(s); // foo
let
で変数を宣言するとブロックスコープを持つ変数になるlet
と for
var fs = [];
for (var i = 0; i < 3; ++i) {
var f = function () {
console.log(i);
};
fs.push(f);
}
for (var i = 0; i < 3; ++i) {
fs[i](); // 3, 3, 3
}
i
を参照しているlet
と for
var fs = [];
for (var i = 0; i < 3; ++i) {
var f = (function (i) {
return function () { console.log(i); };
})(i);
fs.push(f);
}
for (var i = 0; i < 3; ++i) {
fs[i](); // 0, 1, 2
}
let
と for
var fs = [];
for (let i = 0; i < 3; ++i) {
var f = function () {
console.log(i);
};
fs.push(f);
}
for (var i = 0; i < 3; ++i) {
fs[i](); // 0, 1, 2
}
for
の初期化節で let
を使うconst
)const answer = 42;
answer = 0; // compile error
const s = "foo";
{
const s = "bar";
console.log(s); // bar
}
console.log(s); // foo
const
もブロックスコープを持つvar myRandom = function (x, y) {
var range = y - x;
return x + (Math.random() * range);
};
var pow2 = function (x) { return x * x };
var myRandom = (x, y) => {
var range = y - x;
return x + (Math.random() * range);
};
var pow2 = x => x * x;
(x) => { ... }
を x => { ... }
と略記可(foo) => { return bar; }
を (foo) => bar
と略記可function
記法では this
の扱いについて違いがあるthis
の扱い)var obj = {
f: function () {
setTimeout(function () {
console.log(this.x);
}, 1000);
},
x: 42
};
obj.f(); // undefined
this !== obj
となってしまうthis
の扱い)var obj = {
f: function () {
var that = this;
setTimeout(function () {
console.log(that.x);
}, 1000);
},
x: 42
};
obj.f(); // 42
this
に別名を付けるthis
の扱い)var obj = {
f: function () {
setTimeout((function () {
console.log(this.x);
}).bind(this), 1000);
},
x: 42
};
obj.f(); // 42
Function.prototype.bind
を使うthis
の扱い)var obj = {
f: function () {
setTimeout(() => {
console.log(this.x);
}, 1000);
},
x: 42
};
obj.f(); // 42
this
を関数内でも使える (this === obj
)class
)class
という単語自体は古くから予約語だったりするclass
)class Application {
constructor(name) {
this.name = name;
}
start() {
document.addEventListener("DOMContentLoaded", (event) => {
this.domDidLoad(event);
});
}
domDidLoad(event) {
console.log(event);
console.log(this);
console.log(`Application ${this.name} start...`);
}
}
extends
, super
)class MyApplication extends Application {
constructor(name, canvasId, fps = 60) {
super(name);
this.canvasId = canvasId;
this.fps = fps;
}
domDidLoad(event) {
super.domDidLoad(event);
this.canvas = document.getElementById(this.canvasId);
this.context = this.canvas.getContext("2d");
setTimeout(() => this.draw(this.context), 1000 / this.fps);
}
draw(ctx) {
ctx.fillStyle = "#def";
ctx.fillRect(0, 0, 640, 480);
}
}
this
の扱い)document.addEventListener("DOMContentLoaded", (event) => {
this.domDidLoad(event);
});
setTimeout(() => this.draw(this.context), 1000 / this.fps);
this
の扱い)document.addEventListener("DOMContentLoaded", function (event) {
this.domDidLoad(event);
});
setTimeout(function () { this.draw(this.context); }, 1000 / this.fps);
function
でこう書くことはできないthis
の扱い)document.addEventListener("DOMContentLoaded", this.domDidLoad);
this
の扱い)document.addEventListener("DOMContentLoaded", this.domDidLoad.bind(this));
setTimeout(this.draw.bind(this, this.context), 1000 / this.fps);
Function.prototype.bind
を使う場合function * range(n) {
for (var i = 0; i < n; ++i) yield i;
}
const gen = range(3);
console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: undefined, done: true }
function *
と yield
で中断できる関数を作ることができる
function * range(n) {
for (var i = 0; i < n; ++i) yield i;
}
for (var i of range(3)) {
console.log(i); // 0, 1, 2
}
for
– of
でジェネレータの値を列挙できるfunction * range(n) {
for (var i = 0; i < n; ++i) yield i;
}
console.log([...range(2), ...range(3)]); // [ 0, 1, 0, 1, 2 ]
...
でジェネレータを展開できるUint8Array
, Float32Array
, ..., DataView
)Map
, WeakMap
, Set
, WeakSet
Proxy
, Reflect
Promise
Symbol
var xs = new Float32Array(3);
console.log(xs); // [ 0, 0, 0 ]
var ys = new Uint8Array([-1, 0, 255, 256]);
console.log(ys); // [ 255, 0, 255, 0 ]
var zs = new Uint8ClampedArray([-1, 0, 255, 256]);
console.log(zs); // [ 0, 0, 255, 255 ]
new
の際に配列長か Array
か ArrayBuffer
を与えるArrayBuffer
と型付き配列var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var i32 = new Int32Array(buf);
var ui8 = new Uint8Array(buf);
f64[0] = 0.1;
console.log(f64); // [0.1]
console.log(i32); // [-1717986918, 1069128089]
console.log(ui8); // [154, 153, 153, 153, 153, 153, 185, 63]
ArrayBuffer
である
ArrayBuffer
を共有すると内容も共有されるDataView
var buf = new ArrayBuffer(4);
var view = new DataView(buf);
view.setUint8(0, 0xA0);
console.log(view.getInt32(0)); // -1610612736
console.log(view.getInt32(0, true)); // 160
DataView
を用いるとよいtrue
を指定Map
var map = new Map();
var key1 = {};
var key2 = {};
var key3 = key1;
map.set(key1, "foo");
map.set(key2, "bar");
console.log(map.get(key2)); // bar
console.log(map.get(key3)); // foo
for (var key of map.keys()) console.log(key); // {} {}
WeakMap
var map = new WeakMap();
var key1 = {};
var key2 = {};
var key3 = key1;
map.set(key1, "foo");
map.set(key2, "bar");
console.log(map.get(key2)); // bar
console.log(map.get(key3)); // foo
console.log(typeof map.keys === "undefined"); // true
Map
Set
var set = new Set([1, 1, 2, 3, 5, 8]);
set.add(2).add(3).add(5).add(7).add(11);
console.log(set); // [ 1, 2, 3, 5, 8, 7, 11 ]
console.log(set.has(4)); // false
console.log(set.has(5)); // true
WeakSet
var set = new WeakSet();
var key1 = {};
var key2 = {};
var key3 = key1;
set.add(key1);
console.log(set.has(key2)); // false
console.log(set.has(key3)); // true
Set
WeakMap
と同じく列挙不可Proxy
var obj = {};
var handler = {
get(target, name) { return target[name] / 2; },
set(target, name, val) { target[name] = val * 2; }
};
var proxy1 = new Proxy(obj, handler);
var proxy2 = new Proxy(proxy1, handler);
var proxy3 = new Proxy(proxy2, handler);
proxy3.foo = 42;
console.log(proxy3.foo); // 42
console.log(proxy2.foo); // 84
console.log(proxy1.foo); // 168
console.log(obj); // { "foo" : 336 }
Reflect
var obj = {};
var handler = {
get(target, name) { return Reflect.get(target, name) / 2; },
set(target, name, val) { Reflect.set(target, name, val * 2); }
};
var proxy1 = new Proxy(obj, handler);
var proxy2 = new Proxy(proxy1, handler);
var proxy3 = new Proxy(proxy2, handler);
proxy3.foo = 42;
console.log(proxy3.foo); // 42
console.log(proxy2.foo); // 42
console.log(proxy1.foo); // 42
console.log(obj); // { "foo" : 84 }
Promise
then
のメソッドチェーンで処理順を制御し、catch
でエラー処理をするPromise
オブジェクトを返す API を用意しておくとよいPromise
new Promise((resolve, reject) => {
setTimeout(() => resolve("A"), 1000);
}).then((str) => {
console.log(str); // A
return new Promise((resolve, reject) => {
setTimeout(() => resolve("B"), 1000);
}).then((str) => {
console.log(str); // B
return Promise.reject(new Error("C"));
});
}).catch((err) => {
console.log(err.message); // C
return "D";
}).then((str) => {
console.log(str); // D
});
console.log("Start!");
Symbol
var sym1 = Symbol("foo");
var sym2 = Symbol("bar");
var sym3 = Symbol("bar");
console.log(sym1 == sym2); // false
console.log(sym2 == sym3); // false
console.log(sym3 == sym1); // false
Symbol.iterator
var obj = { };
obj[Symbol.iterator] = function () {
return {
next: function () {
return (this.i < 3) ?
{done: false, value: this.i++} : {done: true};
},
i: 0
}
};
for (var x of obj) console.log(x); // 0 1 2
for
– of
で列挙できるObject.assign
var obj = {foo: "bar", x: 42};
Object.assign(obj, {foo: "baz"}, {hoge: "piyo"});
console.log(obj); // { "foo" : "baz", "x" : 42 , "hoge" : "piyo" }
Object.setPrototypeOf
var proto = {hoge: "piyo"};
var obj = {foo: "bar"};
Object.setPrototypeOf(obj, proto);
console.log(Object.getPrototypeOf(obj) === proto); // true
console.log(obj.foo); // bar
console.log(obj.hoge); // piyo
obj.hoge = "fuga";
console.log(obj.hoge); // fuga
__proto__
の代替として利用可function foo() { }
console.log(foo.name); // foo
var bar = function () { };
console.log(bar.name); // bar
console.log((function () { }).name === "") // true
name
プロパティで関数名を取得できるString
console.log("🍣".codePointAt(0)); // 127843
console.log(String.fromCodePoint(12354, 32, 127843)); // あ 🍣
console.log("A".repeat(3)); // AAA
console.log("heart".includes("ear")); // true
console.log("heart".startsWith("hear")); // true
console.log("heart".startsWith("ear", 1)); // true
console.log("heart".endsWith("art")); // true
Array
var obj = {0: "foo", 1: "bar", length: 2};
console.log(Array.from(obj)); // ["foo", "bar"]
function * gen() { yield 2; yield 3; yield 5; }
console.log(Array.from(gen())); // [2, 3, 5]
console.log([2, 3, 5, 7].find(x => x > 3)); // 5
console.log([2, 3, 5, 7].findIndex(x => x > 3)); // 2
console.log(new Array(3).fill(42)); // [42, 42, 42]
from
: 「配列のような」オブジェクトを配列に変換find
: 条件に一致する最初の要素を得るfindIndex
: 条件に一致する最初の要素の添字を得るNumber
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(-Infinity)); // false
console.log(Number.isFinite(NaN)); // false
console.log(Number.isInteger(42.00000)); // true
console.log(Number.isInteger(42.00001)); // false
console.log(Number.isSafeInteger(1e+15)); // true
console.log(Number.isSafeInteger(1e+16)); // false
console.log(Number.EPSILON); // 2.220446049250313e-16
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
console.log((Number.MIN_SAFE_INTEGER - 1) | 0); // 0
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log((Number.MAX_SAFE_INTEGER + 1) | 0); // 0
Math
console.log(Math.sign(-42)); // -1
console.log(Math.cosh(Math.log(2))); // 1.25
console.log(Math.trunc(-3.5)); // -3
console.log(Math.cbrt(27)); // 3
console.log(Math.hypot(3, 4)); // 5
sign
: 符号(-1, 0, +1)cosh
, sinh
, tanh
: 双曲線関数trunc
: 0 方向への丸めcbrt
: 立方根hypot
: 二乗和の平方根Array
, RegExp
, Function
, Promise
, Boolean
, Number
, String
, Map
, Set
を継承したクラスを定義できるimport
, export
import
, export
// app.js
var utils = require("./utils");
utils.hello(); // Hello, world!
console.log(utils.answer); // 42
// utils.js
function hello() { console.log("Hello, world!"); }
var answer = 42;
module.exports = { hello: hello, answer: answer };
import
, export
// app.js
import utils from "./utils";
utils.hello(); // Hello, world!
console.log(utils.answer); // 42
// utils.js
function hello() { console.log("Hello, world!"); }
var answer = 42;
export default { hello: hello, answer: answer };
import * as
// app.js
import * as utils from "./utils";
utils.hello(); // Hello, world!
console.log(utils.answer); // 42
// utils.js
export function hello() { console.log("Hello, world!"); }
export var answer = 42;
import { ... }
// app.js
import { hello, answer } from "./utils";
hello(); // Hello, world!
console.log(answer); // 42
// utils.js
export function hello() { console.log("Hello, world!"); }
export var answer = 42;
We are hiring!
UNIPRO Inc.