上手く説明できるかどうか分かりませんが、functionの方が古くからある記法で、function内で定義したthisは、呼び出し時に(誰がその関数をcallしたかによって)thisの中身が変わります。例えばcallやapplyを使用して、thisの中身を後から変えることもできます。
var obj1 = {i:1, f:function(){return this.i;}};
console.log(obj1.f()); // obj1が呼び出しているので、thisにはobj1が入っています
// 1
window.i = 50
obj1.f.apply(window); // applyを使用してwindowのスコープでfを実行すると、thisはwindowに
// 50
この性質で混乱するのが、例えばsetTimeoutを呼んだ処理です。オブジェクト内で作成したSetTimeoutの引数である無名関数は、トップレベルでのcallになるのでwindowスコープとなり、期待とは違いthis.countはwindow.countを指すことになります。
var obj = {
count : 10,
doSomethingLater : function (){
setTimeout(function(){ // この関数のスコープはwindow
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater(); // コンソールに "NaN" と表示。 "count" プロパティは window スコープではないため。
この問題に対して、従来は以下のようにbindなどでthisとなるスコープを拘束する必要がありました。
var obj = {
count : 10,
doSomethingLater : function (){
setTimeout(function(){
this.count++;
console.log(this.count); // 無名関数のスコープを、doSomethingLaterのthisで拘束!
}.bind(this), 300);
}
}
obj.doSomethingLater();
// 約0.3秒後に11と表示
一方、アロー関数では作成時に(?ちょっとこの表現自信ないです)thisが決まります。これを使えば先ほどのsetTimeoutの例はシンプルにこう書けます。
var obj = {
count : 10,
doSomethingLater : function (){
setTimeout(() => {
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater();
// 約0.3秒後に11と表示
アロー関数の方が直感的なので使いやすいですが、例えばインスタンスメソッドには使えないなどいくつかの制約があります。
また、アロー関数自体をサポートしていないブラウザも僅かにあるのでご参考まで。アロー関数で書いたコードは、bindやapplyなどを使ってアロー関数無しでも実現できるので、多くの場合開発時はアロー関数で書き、babelなどを使ってfunctionにトランスパイルすることが多いと思います。