結論
CoffeeScript みたいに this を bind するアロー関数 =>
と bind しない関数 ->
の2つを用意してくれないと辛いと思った。
まぁ ECMAScript 的な書き方をしていないだけかもしれないけど。。。
JavaScript のモジュールの作り方
JavaScript で prototype などを使ってモジュールを作る時の書き方の一つとして次のような書き方がある。
'use strict';
function Obj (value) {
this._value = value;
}
Obj.prototype.value = function (val) {
if (val) {
this._value = val;
return this;
} else {
return this._value;
}
};
Obj.prototype.setKey = function (key) {
return { key: key, value: this.value() };
};
module.exports = Obj;
これを今回 「ECMAScript2015 ではアロー関数がある!簡潔に書ける!!」とか調子乗って使ったら見事にはまった。
this.value is not a function
今回の変更は以下の通り。 xxx = function () {}
の部分をアロー関数に変換した。
'use strict';
function Obj (value) {
this._value = value;
}
Obj.prototype.value = (val) => {
if (val) {
this._value = val;
return this;
} else {
return this._value;
}
};
Obj.prototype.setKey = (key) => {
return { key: key, value: this.value() };
};
module.exports = Obj;
そしたら上の this.value is not a function
を食らうはめに。。。
実は this が bind されないことで救われていた JavaScript
一応自分の中での this の理解の確認も兼ねてちょっと丁寧に説明してみる。
もし違ってたらご指摘お願いします :)
もともと js の this は「どこで定義しているか?」ではなく「誰が呼び出しているか?」によって決定する。
例えば
Obj.prototype.doMethod = function () { return this; }
というメソッドがあった時、この時点では this は決定していなくて、
var o = new Obj();
console.log(o.doMethod());
といったコードが実行された時に Obj
オブジェクトのインスタンスが doMethod
を実行してるから、結果として Obj
に紐付いているように見える。
しかし、今回のアロー関数を使う事で(内部的にどう変換されているのかはキチンと把握していないですが。。。)以下のようなコードを書いている事と同義になる。
Obj.prototype.doMethod = (function () {
return this;
}).bind(this);
この bind
メソッドによって関数内部の this が1段上のスコープに存在する this と紐付けられる。
ということで this が Obj ではなく global に紐付けられてもうた。。。
this を bind しないアロー関数がほしいです先生。