function
関数はファーストクラス
JavaScriptの関数は、数値、文字列、配列などと同じように扱う事ができる。すなわち
- 変数に代入できる
- 他の関数の引数として渡せる
- 他の関数の戻り値できる
- 実行時に動的に生成できる
- 匿名リテラルとして表現可能である
といった性質がある。このような性質を持つオブジェクトはファーストクラス(第一級)オブジェクトと呼ばれる。(ここでいうオブジェクトはプログラミングにおける操作対象ぐらいの意味で、オブジェクト指向のオブジェクトではない)
/* 関数を変数に代入できる */ function hoge() { console.log('ほげ'); } // 関数はnameプロパティを持つ、自分自身の関数名である console.log(hoge.name); // => hoge const f = hoge; f(); // => ほげ // 変数に入れてもnameプロパティは変わらない console.log(f.name); // => hoge
関数にプロパティを作成できる(ただし作成する意味はあまりない)
/* 関数にプロパティを作成する。
function fuga() {
// arguments.calleeは自分自身(= fuga)を参照する値
console.log(arguments.callee.count);
}
fuga.count = 100;
fuga(); // => 100
関数式
式の中で関数を作成する方法。
const hoge = function() { console.log('ほげ') } hoge();
関数宣言との違い
- 巻き上げが行われない
- 無名の関数を作れる
よくある用途はArray#forEachに渡す関数
[1,2,3].forEach(function(i) { console.log(i * 2); // => 2, 4, 6 });
メソッド
JavaScriptのメソッドはオブジェクトのプロパティとなった関数。メソッドはthisを通して自分自身の所属するオブジェクトにアクセスできる。
const person = { name: 'Nyan' } obj.greet = function() { // thisは自分自身が所属するオブジェクトを指す console.log(`Hello ${this.name} !`) } obj.greet(); // => Hello Nyan !
メソッドとして定義されてない関数のthisはグローバルオブジェクトとなる。
function g() { console.log(this); } g(); // ブラウザであればwindowオブジェクト, Node.jsならばglobalオブジェクト
アロー関数
関数式の簡潔な代替構文。しかし多少の機能の違いもある
- メソッドにできない(this、arguments、superへのバインドがない)
- コンストラクタにできない
- ジェネレータにできない
[1,2,3].forEach((i) => { console.log(i * 2); // => 2, 4, 6 });
メソッドの中で関数式を書く場合は、アロー関数を使うと意図通りに動作するだろう
const obj ={ rate: 2, f() { [1,2,3].forEach(function(i) => { console.log(i * this.rate); // 関数式のthisはグローバルオブジェクトにバインドされてしまう }); }, a() { [1,2,3].forEach((i) => { console.log(i * this.rate); // アロー関数はthisへのバインドがなく、この環境のthisが引き継がれる }); } } obj.f(); // [NaN, NaN, NaN] obj.a(); // [2, 4, 6]
高階関数
関数を引数にする関数や、関数を戻り値にする関数を高階関数という。高階関数はJavaScriptの用語ではないが、JavaScriptでは空気のように多用される。
var array1 = [3,5,4,1,2]; array1.sort((a, b) => a - b ); // 降順ソート var array2 = [4,3,2,5,1]; array2.sort((a, b) => b - a); // 昇順ソート
Javaのように関数をオブジェクトとして利用することができない(難しい)言語ではストラテジーパターンで代用されています。Javaで配列をソートする場合、Comparatorインターフェースの実装クラスを作る必要があり面倒ですが、スクリプト言語は関数やコードブロックを渡すだけで良く、簡潔に記述できます。
クロージャ
自分自身が定義された環境を参照する関数をクロージャという。
function genCalcTaxRate() { const rate = 1.1; return (price) => price * rate; } const calcTaxRate = genCalcTaxRate(); console.log(calcTaxRate(100)); // => 110
genCalcTaxRateは関数を返す関数である。本来、変数rateはスタック領域に積まれる値であり、genCalcTaxRate関数が終了するとともに失われるはずである。しかし関数の中でアロー関数が定義され、そのアロー関数が変数rateを参照しており、なおかつ、そのアロー関数がreturnされている。こうなるとgenCalcTaxRateが終了しても変数rateはアロー関数に保持されるため失われない。
JSではクロージャも空気のように使われているため意識することは少ない