本記事では、JavaScriptのアロー関数を使用して、関数式のより簡潔なコードを記述する方法を解説します。
JavaScriptのアロー関数とは
ES6のアロー関数は、普通の関数式と比較して短い構文で記述することができます。
次の例では、2つの数値の和を返す(普通の)関数式を定義しています。
let sum = function (a, b) {
return a + b;
};
console.log(sum(10, 20)); // 30
次の例は、上記のsum()関数式と同等ですが、代わりにアロー関数を使用した書き方です。
let sum = (a, b) => a + b;
console.log(sum(10, 20)); // 30;
この例では、アロー関数は1つの式(a + b)を持っているので、式の結果を返します。
ただし、ブロック構文を使用する場合は、returnキーワードを指定する必要があります。
let sum = (a, b) => { return a + b; };
typeof演算子を使うと、アロー関数型の関数を返します。
console.log(typeof sum); // function
以下の例が示すように、アロー関数もFunction型のインスタンスです。
console.log(sum instanceof Function); // true
複数の引数を持つJavaScriptのアロー関数
アロー関数に2つ以上の引数がある場合は、次のような構文になります。
(引数1, 引数2, ..., 引数n) => 処理;
ちなみに、
=> 処理
と
=> { return 処理 }
は同じ意味です。
具体的なコード例
たとえば、数値の配列を降順に並べ替えるには、次のように配列オブジェクトのsort()メソッドを使います。
let numbers = [7, 1, 8];
numbers.sort(function(x, y){
return y - x;
});
console.log(numbers); // [8, 7, 1]
アロー関数の構文で、より簡潔に書くとこうなります。
let numbers = [7, 1, 8];
numbers.sort((x, y) => y - x);
console.log(numbers); // [8, 7, 1]
JavaScriptのアロー関数を1つの引数で使用する場合
アロー関数が1つだけの引数を取る場合は、次のような構文になります。
(引数) => { 処理 }
なお、以下のように括弧を省略することもできます。
引数 => { 処理 }
具体的なコード例
次の例では、文字列の配列を文字列の長さの配列に変換するmap()メソッドの引数として、アロー関数を使用しています。
let names = ['tanaka', 'takahashi', 'honda'];
let lengths = names.map(name => name.length);
console.log(lengths); // [6, 9, 5]
引数が無いアロー関数
アロー関数に引数がない場合は、次のように括弧を使用する必要があります。
() => { 処理 }
具体的なコード例
let sample = () => console.log('引数なしのアロー関数');
sample(); // 引数なしのアロー関数
引数と矢印の間での改行
JavaScriptでは、アロー関数の引数を定義した箇所と矢印(=>)の間に改行を入れることができません。
例えば、以下のようなコードはSyntaxErrorを引き起こします。
let sum = (x, y)
=> x + y;
しかし、以下の書き方であれば問題なく動作します。
let sum = (x, y) =>
x + y;
また、JavaScriptでは、次の例のように、引数と引数の間に改行を入れることもできます。
let sum = (
x,
y
) =>
x + y;
アロー関数内のステートメントと式
JavaScriptでは、次の例のように、式は値として評価されます。
20 + 40;
また、以下のように、特定の処理を行うのがステートメントです。
if (x === y) {
console.log('xはyである');
}
アロー関数中で式だけを使用する場合は、中括弧を使用する必要はありません。
let double = x => x + x;
ただし、ステートメントを使用する場合は、次の例のように中括弧で囲む必要があります。
let sample = parameter => {
throw parameter;
};
JavaScriptのアロー関数とオブジェクトリテラル
次のような例を考えてみましょう。
let setFruit = function (fruit) {
return {name: fruit}
};
let fruitObject = setColor('apple');
console.log(fruitObject.name); // "apple"
setColor()関数式は、value プロパティに引数で指定された色を持つオブジェクトを返します。
アロー関数からオブジェクトリテラルを返すために次の構文を使用すると、エラーが発生します。
引数 => {プロパティ: 引数}
例えば、以下のようなコードではエラーになります。
let fruitObject = fruit => { name: fruit }; // エラー
ブロック・リテラルもオブジェクト・リテラルも中括弧を使うので、JavasScriptエンジンはブロックとオブジェクトを区別することができません。
これを解決するには、次のようにオブジェクトリテラルを丸括弧でくくる必要があります。
let fruitObject = fruit => ({ name: fruit });
JavaScriptのアロー関数と「this」
JavaScriptでは、新しい関数はそれ自身のthis値を定義します。しかし、arrow関数の場合はそうではありません。
次の例をご覧ください。
function Car() {
this.speed = 0;
this.speedUp = function (speed) {
this.speed = speed;
setTimeout(function () {
console.log(this.speed); // undefined
}, 1000);
};
}
let car = new Car();
car.speedUp(50);
setTimeout()関数の無名関数内部では、this.speedはundefinedです。これは、無名関数のthisがspeedUp()メソッドのthisを影で表しているためです。
これを解決するには、次のように匿名関数の内部でシャドウしない変数にthis値を代入する。
function Car() {
this.speed = 0;
this.speedUp = function (speed) {
this.speed = speed;
let self = this;
setTimeout(function () {
console.log(self.speed);
}, 1000);
};
}
let car = new Car();
car.speedUp(20); // 20;
無名関数とは異なり、アロー関数は独自の thisコンテキストを作成するのではなく、それを囲むコンテキストの this 値を取得します。
次のコードは期待通りに動作するはずです。
function Car() {
this.speed = 0;
this.speedUp = function (speed) {
this.speed = speed;
setTimeout(
() => console.log(this.speed),
1000);
};
}
let car = new Car();
car.speedUp(20); // 20;
JavaScriptのアロー関数と引数オブジェクト
アロー関数は、引数オブジェクトを持ちません。
function sample() {
return x => x + arguments[0];
}
let display = show(10, 20);
let result = display(5);
console.log(result); // 15
sample()関数内のarrow関数は、argumentsオブジェクトを参照しています。しかし、このargumentsオブジェクトはsample()関数に属しており、arrow関数に属しているわけではありません。
また、arrow関数はnew.targetキーワードを持ちません。
JavaScript のアロー関数と prototype プロパティ
functionキーワードで関数を定義すると、その関数はprototypeというプロパティを持つようになります。
function sample( message ) {
console.log(message);
}
console.log(sample.hasOwnProperty('prototype')); // true
ただし、アロー関数はprototypeプロパティを持ちません。
let sample = message => console.log(message);
console.log(sample.hasOwnProperty('prototype')); // false