ES6になって、アロー関数が導入されて 「いちいち function hoge() なんて書かなくていいんだ!」と単純に思っていました。
が、違うんですね。アロー関数はこれまでの関数と == ではないと気づいたのでメモ。
違いその1 -- アロー関数は this を持ちません
まずは普通の関数で書いた場合です。結果はエラーになります。 ※ strict モードのときです。
なぜなら、forEach は this = undefined で関数を実行するからです。
let kudamono = {
title: "Fruits",
fruits: ["Banana", "Apple", "Orange"],
show() {
this.fruits.forEach(function(fruit) {
console.log(this.title + ': ' + fruit)
});
}
};
kudamono.show();
// Uncaught TypeError: Cannot read property 'title' of undefined
アロー関数の場合はどうでしょう。
let kudamono = {
title: "Fruits",
fruits: ["Banana", "Apple", "Orange"],
show() {
this.fruits.forEach(
fruit => console.log(this.title + ': ' + fruit)
);
}
};
kudamono.show();
// Fruits: Banana
// Fruits: Apple
// Fruits: Orange
こっちは上手くいきます。アロー関数は this を持っていないので、その外側の this(=この例だと kudamono ですね)になります。
違いその2 -- アロー関数は arguments を持ちません
こっちはOKパターンから。通常の function で定義した場合は arguments をもっているので上手く動きます。
function hoge(a, b, c) {
for (let i of arguments) {
console.log(i);
}
}
hoge(1, 2, 3);
// 1
// 2
// 3
一方、アロー関数の場合は arguments を持ちません。のでエラーになります。
var foo = (a, b, c) => {
for (let i of arguments) {
console.log(i);
}
}
foo(1, 2, 3);
// Uncaught ReferenceError: arguments is not defined
結局何が便利?
だからなに? と思いますが便利なときがあります。
それは、this, arguments を使って別の関数を呼び出すような場合です。
function defer(f) {
this.word = "World";
return function() {
setTimeout(() => f.apply(this, arguments), 1000)
};
}
function hello(arg1) {
console.log(`Hello ${this.word} ${arg1}!`);
}
let h = defer(hello);
h("Doraemon");
// Hello World Doraemon!
アロー関数なので、this も arguments も持ちません。
なので、setTimeout で実行される処理は、その外側の this, arguments が使われるので 「Hello World Doraemon!」 となります。
通常の関数で同じことをしようとすると、 this を束縛したり、 function() に引数の設定をしたりが必要になります。
難しいですが、要はアロー関数は、「自分ではコンテキストを持っていない」という点がポイントかと思っています。
今のコンテキストで、ある固まった処理がしたい、というときに便利なんですかね。