そもそもアロー関数って
ES2015(ES6)から利用可能になった新しい関数定義の構文です。
1文しかない関数の定義が簡素化できます。
定義例
引数も戻り値も無し
余談:戻り値?返り値?を追求した人いました💦
// いままで
const fnc1 = function () {
console.log('SP');
}
// アロー
const arrowFnc1 = () => console.log('SP');
引数有り、戻り値無し
// いままで
const fnc2 = function (p1) {
console.log(p1);
}
// アロー
const arrowFnc2 = (p1) => console.log(p1);
引数無し、戻り値有り
// いままで
const fnc3 = function () {
return 'SP';
}
// アロー
const arrowFnc3 = () => 'SP';
引数有り、戻り有り
// いままで
const fnc4 = function (num) {
return num * 2;
}
// アロー
const arrowFnc4 = num => num * 2;
複数引数有り、戻り有り
// いままで
const fnc5 = function (num,num2) {
return num * num2;
}
// アロー
const arrowFnc5 = (num,num2) => num * num2;
まー、1行で書けてすっきりといった感じでしょうか。
もちろん、複数文の場合でもアロー関数定義できます。
// いままで
const fnc6 = function (num,num2) {
const ans = num * num2;
return ans;
}
// アロー
const arrowFnc5 = (num,num2) => {
const ans = num * num2;
return ans;
}
なんでもかんでもアロー関数定義していいわけではない。
制限事項
制限事項があります!
- アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。
- アロー関数には new.target キーワードがありません。
- アロー関数は、call、apply、bind のような、一般にスコープを確立することを前提としたメソッドには適していません。
- アロー関数はコンストラクターとして使用することはできません。
- アロー関数は本体内で yield を使用することはできません。
今回は制限事項のthisについて検証しようと思います。
アロー関数とthis
制限事項に「アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。」
とありますが、
私は「this、arguments、super への結びつけがない」を「アロー関数ではthisは使えないのでメソッドの定義として使ってはいけない。」と理解しました。
しかし、この文だけだとよくわからないのでアロー関数でのthisについて検証します。
まずは、いままの構文でオブジェクトとメソッドを定義してみました。
// オブジェクト定義
const myObject = {
name : 'SP 太郎',
showName: function () {
console.log(this.name);
}
}
myObject.showName();
実行すると
SP 太郎
期待通りの表示がされました。なんの問題もありません。
アロー関数でメソッドを定義します。
// オブジェクト定義
const myObject = {
name : 'SP 太郎',
showName: () => {
console.log(this.name);
}
}
myObject.showName();
実行すると
Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'name')
と、thisが使えないのでエラーになりました。
本当に使えないのか?ということでthisの値を出力してみました。
// オブジェクト定義
const myObject = {
showName: () => {
console.log(this);
}
}
myObject.showName();
実行すると
undefined
と、this変数は未定義となっているので、使えないのか分かります。
本当に本当につかえないのか??
myObject.createSubObjectのメソッドはfunction関数定義で、
subObject.showNameのメソッドはアロー関数定義しました。
// オブジェクト定義
const myObject = {
name: 'myObject',
createSubObject: function() {
return {
name: 'subObject',
showName: () => {
console.log(this.name);
}
}
},
showName: function() {
console.log(this.name);
}
}
myObject.showName();
const subObject = myObject.createSubObject();
subObject.showName();
実行すると
myObject
myObject
あれ、エラーにならなかった。thisが使えた。。。。
しかし、結果がヘン。
subObject.showName();
の出力も「myObject」となっています。
ということで、
thisが使えないのではなく、thisって何?と評価タイミングがfunction関数とアロー関数で違う
と理解するのが正解だと思います。
上記の「this確認」ソースでthisがundefinedになったのは、myObjectがグローバル定義なので定義時にthisなんて存在しないからでしょう。
thisの評価タイミング
function関数(いままで): 関数が実行される時。
アロー関数: 関数が定義される時。
この評価タイミングを理解したうえでfunction関数にするかアロー関数にするか決めないと、わけのわかならいバグで
填まってしまうので気をつけましょう。
上記サンプルを解説すると
subObjectはcreateSubObjectメソッド実行時に定義しています。
createSubObjectメソッド実行時のthisは「myObject」です。
というこはsubObjectのshowName定義時のthisは「myObject」となります。
なので、subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。
// オブジェクト定義
const myObject = {
name: 'myObject',
createSubObject: function() {
// subObjectはcreateSubObjectメソッド実行時に定義しています。
// createSubObjectメソッド実行時のthisは「myObject」です。
return {
name: 'subObject',
// subObjectのshowName定義時のthisは「myObject」となります。
showName: () => {
// subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。
console.log(this.name);
}
}
},
showName: function() {
console.log(this.name);
}
}
subObject.showNameもfunction関数定義にしてみます。
// オブジェクト定義
const myObject = {
name: 'myObject',
createSubObject: function() {
// このメソッド内のthisは「myObject」
return {
name: 'subObject',
showName: function() {
console.log(this.name);
}
}
},
showName: function() {
console.log(this.name);
}
}
myObject.showName();
const subObject = myObject.createSubObject();
subObject.showName();
subObject.showNameのthisも実行時に評価されるので、期待通りの結果となりました。
myObject
subObject
この検証から、クラスやオブジェクトのメソッドでは、アロー関数は使ってはいけない。となります。
Vue.jsのメソッドのマニュアルに
アロー関数は this を介してコンポーネントのインスタンスにアクセスできないため、メソッドを宣言する際に使用することは避けてください。
と書いてあるのは、これらの理由からです。注意しましょう。
じゃ、どこで使う
Array.filterとかのコールバック関数とかで、無名メソッドを定義したいときに使うのがよいかと。
// いままで
const filteredList = list.filter(function (e) {
return !e.del
});
// アロー関数
const filteredList = list.filter(e => !e.del);
以上です。