memolu

いろいろメモってます

ES6 - Arrow Function を解説してみる

本連載について

第二回はArrow Function(アロー関数)を学びます。 本連載では少しづつES6について記載していこうと思います。 発表されてから久しいですが、まだ習得されていない方は今からでも勉強していきましょう。

Arrow Function

今回はArrow Functionです。直訳したままアロー関数と呼ばれています。
Arrow Functionとは、関数を定義する際に従来のfunctionではなく=>という表記を使って処理を記述することができます。
(この記号はFat Arrowと呼ぶそうです)
使い方は後述しますが、ざっくり言えば関数の記述をより簡単にするものです。
また、Arrow Functionの中ではthisの扱い方が変わるため、こちらも後述します。

ブラウザサポート

ブラウザサポートについては以下をご確認ください。

ECMAScript 6 compatibility tablehttp://kangax.github.io/compat-table/es6/#arrow_functionskangax.github.io

Arrow Functionの使い方

まずは、さっそく使ってみましょう。
従来のfunctionを使った場合とArrow Functionを使った書き方で違いを見てみます。

// function
var add = function(x,y)  {
    return x + y;
};

// Arrow Function
var add = (x, y) => {
    return x + y;
};

functionを使った場合に比べ、Arrow Functionではfunction(){}が省略され、()=>{}で表されていることがわかります。
処理の内容によってはさらに記述を簡略化することが可能です。
いくつかに分けて解説いたしますので以下をご覧ください。

関数に引数をとらない場合

空の()を使用します。

var add = () => {
    return 'Hello!';
};

引数が一つの場合

()を省略可能です。

var add = x => {
    return x + 1;
} 

returnする値が一つの場合

{}とreturn文を省略できます.

var add = x => x + 1;

このように今までのfunctionを使う構文に比べかなりすっきりと記載することができるようになっています。 例えば、map関数などを使用した場合にコード量を減らすことが目に見えて削減することができます。

map関数で応用

var arr = [0, 1, 2, 3];

// function構文
var map_1 = arr.map(function(x) {
    return x + 1;
});

// Arrow Function
var map_2 = arr.map( x => x+1 );

Arrow Functionのほうが明らかにシンプルなことが分かります。 このように記述量を短くしてコードをより簡潔に記述できるようになりました。 このあたりからES6では、letやconst然り、コードの見通しがよくなるように言語仕様から改善しようとする動きが読み取れます。

thisの扱い方

次はthisの振る舞いについて解説します。
冒頭の説明でArrow Functionを使うとthisの扱い方が変わるということを説明しました。 どのように変わるかというと、Arrow Functionでは関数が定義されているスコープ内のthisが、関数内のthisとして結び付けられるにとなります。
これだけですとわかりづらいため、functionを使った場合とどのように変わるのか見ていきましょう。
まずは今まで、つまりES5までのthisの振る舞いを説明いたします。

今までのthis

今までjavascriptにおけるthisは実行時のコンテキストによって決まる部分でした。 これらをいくつかに分けて説明いたします。

関数呼び出し時

関数を呼び出した場合、関数内のthisはグローバルオブジェクトを指します。

function hoge() {
    return this;
}
console.log(hoge); // window

オブジェクトのメソッド呼び出し時

オブジェクトのメソッドとして呼び出した場合、thisはそのオブジェクト自身を指します。

// thisにはオブジェクトobjが格納されている
var obj = {
    name: 'hoge',
    sayName: function() {
        return 'my name is ' + this.name;
    } 
};

console.log(obj.sayName()); // my name is hoge

call()・apply()を使用

call()もしくはapply()を使うとthisの値を意図的に書き換えることが可能です。

// callで呼び出すとthisは引数で渡した値になる
var obj = {
    name: 'hoge',
    sayName: function() {
        return 'my name is ' + this.name;
    } 
};

var obj2 = {
    name: 'hogehoge'
};

console.log(obj.sayName()); // my name is hoge
console.log(obj.sayName.call(obj2)); // my name is hogehoge

bind()を使用

bind()を使用するとcall()など違い、thisを固定した新しい関数を生成します。

function sayName() {
    return this.name;
}
var human = {
    name: 'hoge'
};
var humanSayName = sayName.bind(human);
humanSayName(); // hoge

コンストラクタ使用時

newを使ってコンストラクタを実行した場合は、thisは生成されるインスタンスオブジェクトを参照します。

function Human(name) {
    this.name = name;
}
Human.prototype.sayName = function(){
    return 'My name is ' + this.name;
}

var hoge = new Human('hoge');
console.log(hoge.sayName()); // My name is hoge

thisのまとめ

いくつか例に出してみましたがこんなところかと思います。 結果としてthisは以下の様にまとめられます。

  • オブジェクトのメソッドである場合は、そのオブジェクトを指す
  • .call()、.apply()でthisとして参照するオブジェクトを指定して呼び出す場合は、指定されたオブジェクトを指す
  • .bind()でthisとして参照するオブジェクトを紐付けた新しい関数を生成した場合は、紐付けられたオブジェクトを指す

Arrow Functionでのthis

thisの基本をある程度把握できましたら、Arrow Function内でのthisの振る舞いについても理解しましょう。 といっても今までのようなコンテキストに左右されるより、むしろ仕様は簡単になりました。

例えばコンストラクタの場合以下のようになります。 少し長いですが、function構文と比べて書いています。

// function構文
function Human() {
    this.name = 'hoge';
    this.button = document.querySelector('.button');

    this.handleEvents();
}

Human.prototype.handleEvents = function() {
    var self = this;
    this.button.addEventListener('click', function() {
        return self.name;
    });
}

// Arrow Function
function Human() {
    this.name = 'hoge';
    this.button = document.querySelector('.button');

    this.handleEvents();
}

Human.prototype.handleEvents = function() {
    this.button.addEventListener('click', () => this.name);
}

上記コードはDOM要素にイベントハンドラーを登録してクリックされた際に名前を返すように設定しました。
両者で一番大きな違いはvar self = this;の記述がArrow Functionではありません。 functionを使用した場合は、イベントリスナー内のthisがクリックしたDOM要素(上記いえばthis.button)に向いてしまうため、var self = this;のようにしていったんthisとして使いたい値を別の変数に置き換えておくのが慣例でした。
それに対しArrow Functionを見るとthisの値はそのままでも動作しています。
上述した、Arrow Functionでは関数が定義されているスコープ内のthisが、関数内のthisとして結び付けられるの正体ということになります。

Arrow Functionのまとめ

Arrow Functionはコードの記述を減らせることが大きなメリットです。
学習コストも低いため少し触れば誰でも理解できる内容ですし、見通しのいいコードのを作る機能として一役買ってもらえそうです。 thisの振る舞いについても少し慣れが必要そうですが、分かりづらかったthisの扱いを整理して、不本意な変数の生成(var self = this;)などを防ぐために実装されていることを考慮すると自然に使えるかもしれません。 利用環境はブラウザサポートの状況を顧みても限定的にならざるを得ませんが、プロジェクトと相談してぜひ活用してみてください。