Help us understand the problem. What is going on with this article?

JavaScript文法(12) ES6の新機能

More than 3 years have passed since last update.

この記事の内容

  • ES6の新機能について
  • 従来のJavaScript(ES5)から、どのように強化されたか

目次

(1) 学習環境の構築と基本的な書き方
(2) 変数とデータ型
(3) 演算子および配列
(4) 制御構文と関数
(5) 関数の応用1
(6) 関数の応用2
(7) オブジェクトの基礎
(8) JavaScriptのオブジェクト指向プログラミング1 概要
(9) JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承
(10) JavaScriptのオブジェクト指向プログラミング3 多態性
(11) JavaScriptのオブジェクト指向プログラミング4 カプセル化
(12) ES6の新機能について <-- この記事の内容

ECMAScript バージョン6 (ES2015) について

一連の文法記事の最後として、通称ES6から搭載された新機能について、いくつかピックアップして観ていく。なお、ES6は、2015年6月に制定された規格である。詳細は各種ネット記事などを参照のこと。

BabelでES6を試す

2016年現在、まだES6が各種ブラウザ等で確実に機能が実装されているとは言いがたい状況である。そこで、ES6の機能が確実に実行できる環境が「Babel」のサイトにある。

http://babeljs.io/repl/

本来「Babel」は、ES6の機能を使って記述したJavaScriptの命令を、従来のJavaScriptのコード(ES5)に変換してくれるツールである。「altJS」のひとつと言っていいかと。上記のページは、ツールを導入する前にWeb上で手軽にBabelの機能を試せるページとなっている。今回の内容をBabelで変換かけてみると、どのような従来のコードに変換されるかを見てみても面白いかと思う。

ES6の新機能まとめ

const と let

従来のJavaScriptには、定数というものが存在していなかった。ES6で const というキーワードを使えば、定数を実現できる。

bs12_01.js
const USER_MAX_VALUE = 100;
USER_MAX_VALUE = 200;          // 定数は上書きできない旨のエラーが出る
console.log(USER_MAX_VALUE);   // 2行目が無ければ 100 と表示される

次にlet。以前の記事のとおり、ifやforなどのブロック内で宣言された変数は var をつけていてもブロックの外で参照できる。少々問題かなと思ってしまう。そこでES6ではブロックスコープを実現できる新しい要素として let というキーワードが追加された。 var ではなく let を使ってブロック内で変数を宣言すると、ブロックの外で該当の変数を参照できなくなる。

bs12_02.js
if(true) {
  var a = 1;
  let b = 2;
}

console.log(a);    // 1 と表示される
console.log(b);    // bは定義されていない旨のエラーが出る

連想配列専用のオブジェクト Map

JavaScriptで連想配列を使うには、 Object 型のオブジェクトを作成して、プロパティに値を設定する形で使う旨、以前は説明した。ES6からは、Map という型のオブジェクトが追加された。わざわざ Object 型のオブジェクトを利用しなくても連想配列を利用できる。データの登録には set メソッド、指定したキーに紐づいた要素を取得するには get メソッドを利用する。

bs12_03.js
// 新しいMapオブジェクトの生成
var map = new Map();

// mapにデータを新規登録
map.set("name", "田中 太郎");

// mapの指定要素を参照
console.log(map.get("name"));

集合体オブジェクト Set

Map と同時に Set がES6で追加された。SetはJavaのSetインターフェイスと同じく、集合体の形式でデータを管理するためのもの。同じデータを2個以上、重複してデータを管理することができない、という特徴がある。データの登録には add メソッドを使い、そのSetの中にデータがあるかどうかを調べるには has メソッドを使う。

bs12_04.js
// 新しいSetオブジェクトの生成
var set = new Set();

// setにデータを新規登録
set.add("田中");
set.add("鈴木");
set.add("佐藤");
set.add("高橋");

if(set.has("佐藤")) {
  console.log("佐藤さんは、います。");    // この行は実行される
}

for-of文

従来のJavaScriptには for-in 文があった。イテレータのように配列や連想配列から1件ずつ取り出してくれるものである。ただし、for-in文は、通常の配列の場合はインデックス(0, 1, 2, ... といった配列の添字)を、連想配列の場合はキーを1件ずつ取り出す形になる。

bs12_05.js
var score = [70, 65, 55, 80, 100];

for(var s in score) {
  console.log(s);
}
bs12_05.jsの実行結果(一例)
0
1
2
3
4

ES6で追加された for-of 文では、インデックスやキーではなく、値を1件ずつ取得してくれる。

bs12_06.js
var score = [70, 65, 55, 80, 100];

for(var s of score) {
  console.log(s);
}
bs12_06.jsの実行結果(一例)
70
65
55
80
100

なお、for-of文は、MapやSetでも利用できる。

アロー関数

匿名関数では関数を定義する場合、下記のように書く必要があった。

var f = function(name) {
  console.log("Hello, " + name + "!");
}

f("Taro");    // Hello, Taro! と表示される

ES6で追加されたアロー関数を利用すると、わざわざ function という単語を書く必要がなくなる。

bs12_07.js
var f = (name) => {
  console.log("Hello, " + name + "!");
}

f("Taro");    // Hello, Taro! と表示される

function(name) { ... } と記述していた部分が (name) => { ... } というように短縮して記述できるようになった。

引数が未定義だった場合のデフォルト値の指定が可能に

オーバーロードのときの記事で、引数のチェックをして、引数が定義されていない(undefined)か否かで処理を分ける記述の仕方を観た。

function hello(name) {
  // 引数が無かったら、nameを 名無し にする
  if(typeof name === "undefined") {
    name = "名無し";
  }

  console.log("こんにちは、" + name + "さん!");
}

hello();          // こんにちは、名無しさん! と表示
hello("太郎");    // こんにちは、太郎さん! と表示

ES6では、このようなチェックを自前で記述しなくても、引数が無かった場合のデフォルト値を指定することができるようになった。

bs12_08.js
function hello(name = "名無し") {
  console.log("こんにちは、" + name + "さん!");
}

hello();          // こんにちは、名無しさん! と表示
hello("太郎");    // こんにちは、太郎さん! と表示

これで、引数があっても無くても、hello 関数が実行できる。

class と extends が追加

以前、JavaScriptには class キーワードが無いと書いたが、あくまでも「ES5までの」JavaScriptは、であり、ES6から class キーワードが追加された。extends キーワードも追加されたため、よりオブジェクト指向プログラミングらしい記述ができるようになった。

bs12_09.js
class Animal {
  // コンストラクタは constructor という名前のメソッドで固定
  constructor(name, voice) {
    // プロパティの定義
    this.name  = name;
    this.voice = voice;
  }

  // メソッドの定義
  bark() {
    console.log(this.name + "が鳴く:" + this.voice);
  }
}

// Dog クラス(Animalクラスを継承)
class Dog extends Animal {
  constructor(name, voice) {
    // 親クラスのコンストラクタを呼び出す
    super(name, voice);
  }

  // bark() メソッドをオーバーライド
  bark() {
    console.log(this.name + "が吠える:" + this.voice);
  }
}

// Cat クラス(Animalクラスを継承)
class Cat extends Animal {
  constructor(name, voice) {
    super(name, voice);
  }
}

// Dog と Cat の新しいオブジェクトを生成
var pochi = new Dog("ポチ", "わん!");
var tama  = new Cat("タマ", "にゃー!");

pochi.bark();       // ポチが吠える:わん! と表示される
tama.bark();        // タマが鳴く:にゃー! と表示される

※補足:スクラッチパッドで実行していて、

SyntaxError: redeclaration of let Animal
@Scratchpad/1:2:7

このようなエラーが文法的な記述ミスなど無いのに表示された場合は、スクラッチパッドの上部のメニューから「実行メニュー」→「再読み込みして実行」をしてみると、エラーが回復する場合がある。

発展的内容:Promiseオブジェクト

非同期処理やコールバック関数の記事で、以下の様なコードを扱った。

// 非同期処理の定義
function timeoutFunc(callback, delay) {
  setTimeout(function() {
    console.log("非同期処理 実行");
    callback();
  }, delay);
};

// プログラムの処理本体
console.log("プログラム 開始");
timeoutFunc(function() {
  console.log("非同期処理 終了");
}, 1000);

ES6からは、非同期処理を専門に扱うPromiseオブジェクトというものが追加された。コールバック関数とは別の方法で非同期処理を実装できる。以下は一例。

bs12_10.js
// Promiseオブジェクトを使った非同期処理の定義
function timeoutFunc(delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      // resolve関数を介してconsole.logを実行
      resolve(console.log("非同期処理 実行"));
    }, delay);
  });
};

// プログラムの処理本体
console.log("プログラム 開始");

// then関数の引数にコールバックで実行したい処理を指定
timeoutFunc(1000)
  .then(function() {
    console.log("非同期処理 終了");
  });

Promiseオブジェクトの利点のひとつに、ネスト地獄に陥る可能性が低くなる、というものがある。たとえば、コールバック関数の中でコールバック関数を呼び出すような書き方をした場合、以下のような記述になってしまう。

// 非同期処理の定義
function timeoutFunc(callback, delay) {
  setTimeout(function() {
    console.log("非同期処理 実行");
    callback();
  }, delay);
};

// プログラムの処理本体
console.log("プログラム 開始");
timeoutFunc(function() {
  timeoutFunc(function() {
    timeoutFunc(function() {
      timeoutFunc(function() {
        console.log("非同期処理 終了");
      }, 1000);
    }, 1000);
  }, 1000);
}, 1000);

幾重にもネストしなければならなくなる。これをPromiseオブジェクトを利用した形に書き換えると、以下のようになる。

bs12_11.js
// Promiseオブジェクトを使った非同期処理の定義
function timeoutFunc(delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      // resolve関数を介してconsole.logを実行
      resolve(console.log("非同期処理 実行"));
    }, delay);
  });
};

// プログラムの処理本体
console.log("プログラム 開始");

// then関数の引数にコールバックで実行したい処理を指定
timeoutFunc(1000)
  .then(function() {
    timeoutFunc(1000);
  })
  .then(function() {
    timeoutFunc(2000);
  })
  .then(function() {
    timeoutFunc(3000)
      .then(function() {
        console.log("非同期処理 終了");
      });
  });

これが利点のひとつである。

なお、Promiseオブジェクトをまともに利用するためには、他にも知っておきたい要素がたくさんあるが、当記事ではここまでとさせていただく。興味ある人はググるなどして、更なる詳細を調べてほしい。

その他の新機能

また、他にもES6からの新しい機能は沢山あるが、紹介しきれないのと、少し難しい話になるものもあるため、色々と興味がある人は、以下のようなサイトを参照してみると良いかと。(下のサイトは全て、英語圏のサイトである点、注意。)

ECMAScript 2015 Language Specification
http://www.ecma-international.org/ecma-262/6.0/

ECMAScript 6: New Features
http://es6-features.org

ECMAScript 6 compatibility table
http://kangax.github.io/compat-table/es6/


JavaScriptの基礎編としての「文法」については以上となる。実践編としての「Webページ(HTML/CSS)におけるJavaScriptの使い方(イベント、DOMなど)」については、別の機会に。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした