iq29 diary

EG.LAB 開発日記

今更 ES2015 まとめた

今更 ES2015 まとめた

この記事を整形しただけです
ES2015について (ES6) · takahashiakira/tech_for_web Wiki · GitHub)

Class

ES5 における prototype 構文にあたる

class Greet {
  constructor(name) {
    // プロパティ
    this.name = name;
  }
    
  // インスタンスメソッド
  hello() {
    console.log('Hello, My name is ' + this.name)
  }
    
  // スタティックメソッド
  static create(name) {
    return new Person(name);
  }
}

var tom = new Greet('Tom');

// インスタンスメソッドの実行
tom.hello();

// スタティックメソッドの呼び出し
var john = Greet.create("John");

let

ブロックスコープ内のみで利用可能な変数定義。

var foo = 'foo';

{ // この foo は外の foo とはスコープが違うので別物
  let foo = 100;
}

let の宣言をブロックで囲めば、即時関数の中で private な変数を宣言する必要がなくなる

(function () {
  // private
  var food = 'Meow Mix';
}());

console.log(food); // Reference Error
{
  // private
  let food = 'Meow Mix';
}

console.log(food); // Reference Error

const

定数のため再代入できない

const foo = 100;
foo = 'foo' // error

配列は各要素のアドレスを保持しているだけなので、要素の値変更はエラーにならない

const arr = [1, 2, 3];
arr[1] = 10

Arrow Function

// ES5
var func = function (x, y) {
  return x + y;
}
// ES6
var func = (x, y) => {
  return x + y;
}

bind

bind は this の指す先を明示的に指定したオブジェクトに変更できるもので、イベントリスナーなどで this の中身が変わってしまう場合などに役に立つ。アロー関数内では this の値をバインドしなくても利用できる

// ES5
function Person(name) {
  this.name = name;
}

Person.prototype.prefixName = function (arr) {
  return arr.map(function (character) {
    return this.name + character;
  }.bind(this)); // bind しないと this.name が使えない
};
// ES6
function Person(name) {
  this.name = name;
}

Person.prototype.prefixName = function (arr) {
  // this.name をいきなり使える
  return arr.map(character => this.name + character);
};

Method

ハッシュ内のメソッドの function も省略できるようになった

// ES5
var counter = {
  count: 0,
  // メソッド
  increment: function () {
    this.count++;
  }
}
// ES6
var counter = {
  count: 0,
  // メソッド
  increment() {
    this.count++;
  }
}

Parameter

Rest Parameter

引数を可変長で利用できる

function rest (...rest){
  console.log(rest);
}

// 好きなだけ引数を渡せる
rest(1, 2, 3); // [10, 20 ,30]

Default Parameter

関数でデフォルトパラメータを指定できる

function add (a = 1, b = 2){
  return a + b;
}

Template Strings

テンプレートリテラル を利用して特殊文字エスケープする必要がなくなった
JavaScript の テンプレートリテラル を極める!

// バッククオート (`) で囲めば、ちゃんと " はエスケープされる
let text = `This string contains "double quotes" which are escaped.`;
var name = 'Bob';

// 文字列に変数を埋め込めるようになった
console.log('Hello, ${name}.');
// 改行に改行コードを使う必要がなくなった
let text = ( `cat
dog
nickelodeon`
);
let today = new Date();

// 式も文字列内で展開して扱えるようになった
let text = `The time and date is ${today.toLocaleString()}`;

Map

key-value データを扱うクラスである Map を利用できるようになった

var map = new Map();
map.set('key1', 'value1');
map.get('key1'); // "value1"
map.has('key1'); // true
map.delete('key1');
var map = new Map([['k1', 'v1'], ['k2', 'v2']]);
map.get('k1') // "v1"
console.log(map2.size); // 2
map2.clear(); // 全データのクリア

WeakMap

WeakMap は、Key に指定されたオブジェクトに対して弱い参照を持つことでガベージコレクションを妨げないクラスとなっている。そのため繰り返しを伴うメソッドや clear メソッドは存在しないが、キャッシュに利用したり、プライベートプロパティとして利用できる

const privateNames = new WeakMap();

class Foo {
  constructor(name) {
    // name をプライベートプロパティとして保持
    privateNames.set(this, name);
  }

  getName() {
    return privateNames.get(this);
  }
}

Symbol

オブジェクトプロパティのキーとして使うことができるユニークな値を生成。プロパティ名がコンフリクトしないことを保証できるため、文字通りシンボルとして使われるイベント名などの定数や列挙型の値として使うと便利

var syml = Symbol();
var syml2 = Symbol('foo');

syml2.toString(); // "Symbol("foo")"
console.log(syml2 === Symbol('foo')); // false

var obj = {[syml2]: 1};

Object.keys(obj); // []
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
var obj = {
  [Symbok.toStringTag]: 'Foo!'
}
console.log(String(obj)); // "[object Foo!]"

Object.assign(target, source1, source2...)

オブジェクトをターゲットにシャローコピーする。jQuery の $.extend と同様の機能。

var objA = {
 "key1": 1,
}

var objB = {
 "key1": 2,
 "key2": 2
}

// ObjA に objB の要素を上書きコピーする
var objC = Object.assign(objA, objB);

console.log(objA == objC); // true
console.log(objA["key1"] == 2); // true
console.log(objA["key2"] == 2); // true

String

String.includes(string)

文字列の中に引数の文字列が含まれているか真偽値を返す

const string = 'food';
const substring = 'foo';

console.log(string.includes(substring)); // true

String.repeat(n)

文字列を n 回繰り返す

'meow'.repeat(3); // 'meowmeowmeow'

Array

  • Array.from: Array のようなオブジェクトやイテレータを Array に変換
  • Array.of: 引数を要素に持つ配列を生成する
var arr = Array.from('foo');

console.log(arr); // ['f', 'o', 'o']
var arr = MyArray.of[1, 2, 3];

console.log(arr); // [1, 2, 3]
console.log(arr instanceof MyArray); // true

イテレータへの対応として、Map や Set と互換性のあるメソッド keys, values, entries が追加された。その他、配列内で要素をコピーするメソッド copyWithin や、要素を指定の値で埋めるメソッド fill や、find、findIndex が追加された

Promise

非同期処理を抽象化する統一的なインターフェース

// 非同期処理
function wait(time){
  // 引数名は自由
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 処理が成功の場合、resolve の引数の中で then に渡される戻り値を書く
      resolve('wait: ' + time);
    }, time);
  });
}

// then 以下に resolove 時の処理。value で戻り値を受け取る
wait(2000).then(value => {
  console.log(value); // "wait: 2000"
// then をメソッドチェーンにすることもできる
}).then(value => {
  conosle.log(value); // undefined
});

Promiseのエラー処理

// 非同期処理
function getUrl(url) {
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => {
      if (xhr.status == 200) {
        resolve(xhr.statusText);
      } else {
        // 処理が失敗の場合、reject の引数の中で catch に渡される戻り値を書く
        reject(new Error(xhr.statusText));
      }
    }
    xhr.onerror = () => {
      // 処理が失敗の場合、reject の引数の中で catch に渡される戻り値を書く
      reject(new Error(xhr, statusText));
    };
    xhr.send();
  });
}

getUrl('/items').then(res => {
  var items = JSON.parse(res);
  someProcess(items);
// catch 以下に reject 時の処理。e で戻り値を受け取る
}.catch(e => {
  console.error(e);
});

Promise.all

全ての非同期処理が終わるまで待つ

Promise.all([
  // 配列の中で非同期処理を複数実行
  getUrl('/foo'),
  getUrl('/bar')
]).then(res => { // 受け取る戻り値 res も配列
  console.log(res[0]);
  console.log(res[1]);
}).catch(e => {
  console.error(e);
});

co

Generator をベースにしたライブラリ。yield の処理が終わるまで次に進まない。非同期処理の可読性があがる

// ジェネレーター関数で非同期処理を実装
function * getFirstitem() {
  var Items = yield getUrl('/items');
  var item = yield getUrl('items/' + imtes[0].id);
  return item;
}

var co = require('co');

co(function* () {
  // try - catch 文
  try {
    var item = yield getFirstItem(); // ジェネレータ関数を同期処理として実行
    someProcess(item); // item の取得を待ってから実行される
  } catch(e) {
    console.error(e);
  }
});

Generator

処理を停止したり再開したりできる特殊な関数。yield で処理が一旦止まるので、next で次に進める

function* 宣言 (末尾にアスタリスクが付いた function キーワード)

Generator オブジェクトを返すジェネレーター関数を定義

function generator() {
  yield 1;
  yield 2;
  return 3;
}

var g = generator();

// generator1 の処理が全部終わったかどうかは done でわかる
conosle.log(g.next()); // {value: 1, done: false}
conosle.log(g.next()); // {value: 2, done: false}
conosle.log(g.next()); // {value: 3, done: true}

for (let n of generator()) {
  console.log(n);
}

非同期処理との組み合わせ

// 非同期処理
asyncflow(function * () {
  var items = yield getUrl('/items');
  var id = items[0].id;
  var item = yield.getUrl('/items/', + id);
  console.log(item);
});

function asyncflow(generator){
  var g = generator();
  var next = value => {
    var result = g.next(value);
    if (!result.done) {
      promise = result.value;
      promise.then(value => {
        next(value);
      });
    }
  };
  next();
}

import/export

ES2015 では Webpack などのライブラリを使わなくても AMD や CommonJS の記法を扱うことができる

エクスポート

default export

let foo = "foo!";

export default foo;

class Baz {
  constructor() {
    console.log('Baz!');
  }
}

export default Baz;

インポート

import from

import foo from './foo';
import Baz from './baz';

as

名前を変更できる

import {foo as bar} from './foo';

*

全てをインポートできる

import * as util from 'math/addition';

デフォルトのオブジェクトから、どの機能をインポートするか選択する

import React, { Component, PropTypes } from 'react';