アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

ES2015の新記法

この記事はアクトインディ Advent Calendar 2016 3日目になります。 どうぞよろしくお願いします。

ES2015の新記法について、まとめました。

ES2015の新記法

変数の宣言

let

  • 変数の重複を許可しない
  • ブロックスコープ({})を認識する
var x = "foo";

var x = "bar";

let y = "foo";

let y = "bar";
if (true) {
  var i = 5;
}

console.log(i);

if (true) {
  let x = 5;
}

console.log(x);

定数(const)

const TAX = 1.08;
let price = 100 * TAX;

データ型

分類 データ型 概要  
基本型 数値型(number)    
基本型 文字列型(string) シングル/ダブルクォートで囲まれた0個以上の文字の集合  
基本型 真偽型(boolean) true(真)/false(偽)  
基本型 シンボル型(symbol) シンボルを表す(ES2015の新記法)  
基本型 特殊型(null/undefined) 値が空、未定義であることを表す  
参照型 配列(array) データの集合(各要素にはインデックス番号でアクセス可能)  
参照型 オブジェクト(object) データの集合(各要素には名前でアクセス可能)  
参照型 関数 一連の処理(手続き)の集合 ### String型の不思議
let x = new String("foo");
let y = "foo";

x == y
=>true

let z = new String("foo");
x == z
=>false

x, zが一致しないのはnew Stringで生成したものは、objectになります。

参照型になっているからこの現象が起きます。

typeof(x);
=>"object"

x,yが比較して一致するのは、文字列リテラルを比較する場合は、一時的にString型にしているからです。

文字列リテラルを持つ値は、String オブジェクトのあらゆるメソッドを呼び出すことができます。JavaScript は自動的に文字列リテラルを一時的な String オブジェクトに変換し、メソッドを呼び出して、その後一時的に作られた String オブジェクトを破棄します。String.length プロパティを文字列リテラルで用いることもできます :

文法とデータ型

シンボル

  • Rubyのシンボルと違い、symbolで生成されたものはユニーク扱いになる
let x = Symbol('sym');
let y = Symbol('sym');

typeof(x);
=>symbol
x.toString();
=>Symbol(x)
x == y
=>false

Mapオブジェクト

  • 連想配列を管理するためのオブジェクト(今まではオブジェクトリテラルで管理)
  • データの検索が早い

伝統的な書き方

var x = { 'apple': 'りんご',
          'orange': 'みかん',
          'strawberry': 'いちご' }
console.time('associative_array');
x.apple
console.timeEnd('associative_array');

map

var x = new Map([['apple', 'りんご'],
                 ['orange', 'みかん'],
                 ['strawberry', 'いちご']]);
x.set('banana', 'バナナ')

console.time('map');
x.get('apple');
console.timeEnd('map');
x.keys();
x.size

オブジェクトリテラルとの違い

  1. 任意の型でキーを設定できる
    • オブジェクト/NaNでもキーになりうる
  2. マップのサイズを取得できる
    • sizeメソッドで要素数を取得できる
  3. クリーンなマップを作成できる
    • オブジェクトリテラルは、Objectそのもの 配下にはObjectが標準で用意しているプロパティが最初から存在している

キーに関わる3つの注意点

  1. キーは「===」演算子で比較される
  2. 特別なNaNは特別ではない
var x = new Map();
x.set(NaN, 'foo');
x.get(NaN);
  1. オブジェクトの比較には注意
var x = new Map();
x.set({}, "foo");
x.get({});

Setオブジェクト

  • 重複しない値の集合を操作する(初めての概念自体)
let i = new Set([1, 5, 100, 10, 5]);
for (var int of i.values()) {
    console.log(int);
}
  • オブジェクトの比較はMapと同じ

書き方

代入

分割代入

  • 端数は切り捨てられる
  • オブジェクトの場合は、変数の並び順は考慮しなくても大丈夫

配列

let [x, y, z] = [1, 2];

連想配列(オブジェクト)

let associative_array = { x: 1,y: 2, z: 3 }
let { x, z, y } = associative_array;

関数

アロー関数

  • 関数リテラルのfunctionを記入しなくて良い
  • 1行で書く場合は、returnを書く必要がない

関数リテラル

let getSquare = function(num) {
    return num * num;
}

アロー関数

let getSquare = (num) => {
    retun num * num;
}

let getSquare = (num) => num * num;

変数展開

テンプレート文字列

let name = "Tom";
let greet = `Hello ${name}`;

引数

引数のデフォルト値

  • 今までは引数にデフォルト値を渡すことはできなかった
function getSquare(num = 2) {
    return num * num;
}

let getSquare = (num = 2) => num * num;

getSquare(5);

名前付き引数

  • {}を使用することで名前付き引数になる
  • 使用する場合に{}で指定する
let getSquare = ({num = 2}) => num * num;

getSquare({num: 5});

let getSquare = ({num}) => num * num;

getSquare({num: 5});

可変長引数の定義

  • ...(スプレッド演算子)で可変長引数になる
function sum(...nums) {
  let result = 0;
  for (let num of nums) {
      result += num;
  }
  return result;
}

「…」演算子による引数の展開

  • 「…」演算子は、実引数で利用することで、配列(正確にはfor..ofブロックで処理できる)をここの値に展開する
Math.max(1, 3, 5, 4);
let x = [1, 3, 5, 4]
Math.max(x);
=> NaN
Math.max(...x);
=> 5

引数の戻り値

複数の戻り値を個別の変数に代入する

function getMaxMin(...nums) {
    return[Math.max(...nums), Math.min(...nums)];
}

nums = [1, 4, 100, 5, 904580259, 40]
let x = getMaxMin(...nums);

let [max, min] = getMaxMin(...nums);

クラス

定義方法

  • constructorで初期値を定義する
class Member {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getName() {
      return this.firstName + this.lastName;
  }
}

  • 関数として呼び出すことは不可能
  • 定義前のクラスは呼び出せない
let m = Member("foo", "bar");

class Member {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getName() {
    return this.firstName + this.lastName;
  }
}

静的メソッド(特異メソッド)を定義する

  • staticで定義する

class Member { constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  static greet() {
    return "hello"
  }
}

継承する

  • extendsで継承
class Actindi extends Member {
  static service() {
    return "iko-yo";
  }
}

基底クラスのメソッド/コンストラクターを呼び出す(super)

  • superで基底クラスを継承 or 上書き

書き方

// construcor
super(args)

// method
super.method();
class Actindi extends Member {
  constructor(firstName, lastName, post) {
    super(firstName, lastName);
    this.post = post;
  }

  getName() {
    return this.post + super.getName();
  }

}

モジュール

  • exportでアクセスできるようにする

utility.js

export class Member {
  ...
}

export class Actindi {
  ...
}
  • importで取り込む
import { Member, Actindi } from './utility'

let m = new Member("foo", "bar");

importの記法

  • モジュール全体をまとめてインポート
    • asでモジュールの別名を指定しておく
import * as app from './utility'

let m = new app.Member("foo", "bar");
  • モジュール内の個々の要素に別名を付与する
import { Member as MyMember, Actindi as Act } from './utility'

let m = new MyMember("foo", "bar");

メソッド編

配列

for..of(配列を取り出す)

過去

let nums = [1, 2, 3];

for(var i = 0, len = nums.length; i < len; i++){
  console.log(nums[i]);
}

現在

let nums = [1, 2, 3];

for (num of nums) {
  console.log(num);
}

オブジェクト

assign

  • 同名のプロパティは後のもので上書きされる
let x = { name: "foo",
          email: "foo@foo.com",
          login: "var" }

let y = { name: "bar" }
let z = { title: "baz" }
Object.assign(x, y, z)
x
=>Object {name: "bar", email: "foo@foo.com", login: "var", title: "baz"}

処理

Strictモード

  • 「仕様として存在するが、安全性や効率面で利用すべきでない構文」を通知する
分類 Strictモードによる制限型
変数 var命令の省略禁止
変数 将来的に追加予定のキーワードを予約語に追加
変数 引数/プロパティ名の重複を禁止
変数 undefined/nullへの代入を禁止
命令 with命令の利用禁止
命令 arguments.calleeプロパティへのアクセスを禁止
命令 eval命令で宣言された変数を、周囲のスコープに拡散しない
その他 関数配下のthisはグローバルオブジェクトを参照しない(undefinedとなる)
その他 「0〜」の8進数表記は禁止