Vue.jsに書いてある「アロー関数は、this が期待する Vue インスタンスではなく・・・」とは?

More than 1 year has passed since last update.

Vue.jsのドキュメント書いてある


#computed

算出プロパティ(例 aDouble: () => this.a * 2) を定義するためにアロー関数を使用すべきではないことに注意してください。アロー関数は、this が期待する Vue インスタンスではなく、this.a が undefined になるため、親コンテキストに束縛できないことが理由です。


とか


#data

data プロパティ(例 data: () => { return { a: this.myProp }}) でアロー関数を使用すべきではないことに注意してください。アロー関数は、this が期待する Vue インスタンスではなく、this.myProp が undefined になるため、親コンテキストに束縛できないことが理由です。


が見ていて気になったので、thisについての復習も兼ねて調べてみました。


アロー関数式とは

そもそもアロー関数式とは?

ES2015(ES6)から利用可能になった新しいJavaScriptの構文の一つ。

ES6とは、2015年に標準として策定されたJavaScriptの新しい文法です。

簡単に言うと、アロー関数は関数リテラルをシンプルに記述する方法!


記述方法



var vm = new Vue({

data: { a: 1 },
computed: {
aPlus: {
get: () => {
return this.a + 1
},
set: (v) => {
this.a = v - 1
}
}
}
})

上記の例ではfunctionの代わりに=>が使われていますね。

アロー関数は基本的に以下の様に書きます


記述方法

// 従来の関数式

function(){};

// アロー関数
() => {};



特徴

通常の無名関数との違い



  • thisの扱いが違う


  • argumentsオブジェクトを持たない

  • コンストラクタとして振る舞うことはできない


thisの復習

アロー関数では、thisの挙動も従来の関数とは異なります。→ これが最大の特徴

それについて述べる前にまず、これまでのthisの挙動がどのようなものであったかを復習!


関数呼び出しパターン

function show() {

console.log(this);
this.value = 1; // thisはグローバルオブジェクトを指す(※valueはグローバル変数になる)
}

/*グローバルスコープ内*/
show(); // thisはグローバルオブジェクトをさす


thisは、グローバルスコープで呼び出された場合はグローバルオブジェクトを指します。


メソッド呼び出しパターン

var obj = {

value: 10,
show: function() {
console.log(this.value); // thisは呼び出されたオブジェクトを指す
}
}

obj.show(); // 10


オブジェクトのメソッドのなかで呼びされた場合はそのオブジェクトを指します。

メソッドにおいても同様で、そのメソッドにアクセスしたオブジェクト(インスタンス)が、thisになります。


コンストラクタ呼び出しパターン

function obj(value) {

this.value = value;
this.increment = function() {
this.value++;
};
}

// インスタンス生成
var obj = new obj(0);
console.log(obj.value); // 0

obj.increment();
console.log(obj.value); // 1


コンストラクタとして関数を使った場合、

つまりnew演算子でインスタンスを作った場合は、コンストラクタのなかにあるthisは、生成されるインスタンスのことを指します。

newをつけなかった場合は関数呼び出しになるので、thisはグローバルオブジェクトを指してしまう。


apply,call,bind呼び出しパターン

var obj1 = {

value: 1,
show: function() {
console.log(this.value);
}
};

var obj2 = {
value: 3
};

obj1.show(); // 1

obj1.show.apply(obj2); // 3
obj1.show.call(obj2); // 3
let bindFunc = obj1.show.bind(obj2);
bindFunc(); // 3


call,apply,bindこれらのメソッドを使うことで、thisとなるオブジェクトを指定することができます。

thisの最大の特徴は、それが何を指し示すかは文脈によって変化するということ。


アロー関数におけるthis

長々と説明しましたが、アロー関数におけるthis

「文脈に依存せず、宣言された時点で、thisを確定(=束縛)する」これが、アロー関数最大の特徴!

具体的には、定義しているスコープのthisを引き継ぐことになります。

これによってvar self = this;みたいなthisを別の変数で持っておく手法を使わなくて済みます。


注意点



var vm = new Vue({

data: { a: 1 },
computed: {
aDouble: () => {
return this.a * 2 // アロー関数におけるthis
}
}
})

console.log(vm.aDouble); // NaN


なので注意しなければいけないのが、アロー関数のthisは、

functionの時のようにインスタンス内ではそのインスタンスを指すという動きはしません。

なぜなら、アロー関数は呼び出された場所をthisとするという動きをするからです。

呼び出された場所は上記のケースだと、thiscomputedオプションのオブジェクトにあたります。

よって、computedオプションのオブジェクトの中にはaをプロパティ名として持つ要素は存在しないので、this.aundefinedとなるというわけです。

つまり、これが


アロー関数は、this が期待する Vue インスタンスではなく・・・


という文章の意味だったわけです。Vueインスタンスを参照できないことには注意が必要ですね。


まとめ

Vue.jsやらのフレームワークを使っていると、

thisがあちらこちら散らばって何がなんやらという状態になりやすい気がします。

アロー関数を使って関数部分をシンプルに記述することができればコードの見通しも良くなるのですが、アロー関数内でのthisは動きが違うので注意が必要です。


参考文献

インスタンス内において、アロー関数の「this」はインスタンスを参照しない

JavaScriptの「this」は「4種類」??