はじめに
JavaScriptの高階関数などについて概要をまとめました。
概念的で難しく、かなり理解に苦しみました(まだ全て理解できていないと思います…)。
実際のプログラミングにおいて有効利用するにはもっと習熟しなければいけないと感じました。
高階関数
- 関数を返す関数のこと
- 関数をその他のオブジェクトと同様に扱うことで実現されている。このようなことができるプログラミング言語は、第一級関数を持つ、という
コールバック関数
- 他の関数に引数として渡される関数のこと
- 例としては、Array.prototype.map()、Array.prototype.forEach()、setTimeout()など
クロージャ
- クロージャとは、それが内包する変数や関数などをまとめて閉じ込める役割を果たすものである
- JavaScriptの関数は入れ子にすることができる
- 内側の関数は、外側の関数のスコープ内に存在する変数にアクセスできる
- 一方で、内側の関数には、外側の関数の中からしかアクセスできない
- ゆえに、ある関数の内部は閉じられたひとつの範囲となるから、JavaScriptの関数はクロージャである
- 次の例では、関数
counter
の中がまとめて閉じ込められることとなる。他のいくつかのプログラミング言語の感覚では、変数count
は関数counter
が呼び出された後に消滅するように見える。しかし、クロージャであるcounter
は、変数count
と関数countUp
をまとめて閉じ込めるから、関数counter
が生存する限り、変数count
も生存することとなる - なお、「まとめて閉じ込める」とは、「内部の変数などをメンバとして持つ」という意味ではない。次の例において、関数
countUp
がその内部で変数count
を参照しているから、関数countUp
が存在する限り変数count
も「合わせてまとめて閉じ込められている」ということである
クロージャの例
function counter () {
let count = 0;
function countUp () {
count += 1;
return count;
}
return countUp;
}
const myCounter = counter();
for (let i = 0; i < 10; i++) {
console.log(myCounter());
} // 1,2,3,4,5...,10と表示される。
- データと関数を結びつけられるという点で、オブジェクト指向的な技術である。メソッドを一つだけ持つオブジェクトのようなものである
クラス
20240811 コメントにて教示いただいた内容を元に追記
- データと関数をひとつにまとめるならば、ES2015以降ではクラスを用いることができる
クラスの例
class MyClass {
constructor(x) {
this.x = x;
}
incrementX() {
this.x++;
}
get x() {
return this.x;
}
set x(value) {
this.x = value;
}
}
const myClassA = new MyClass(1);
カリー化
カリー化の例
function currying(x) {
return function(y) {
return x + y;
};
}
const currying5 = currying(5);
const currying10 = currying(10);
console.log(currying5(2)); //7
console.log(currying10(2)); //12
- 上の例の関数
currying
は、カリー化しないのならば下の例のようにも書ける
カリー化しない例
function notCurrying(x, y) {
return x + y;
}
console.log(notCurrying(5, 2)); //7
console.log(notCurrying(10, 2)); //12
- なぜカリー化するかというと、関数を部分的に適用することができるからである。前者の例における次の部分で、いわば新しい関数を作成している
部分適用
const currying5 = currying(5);
const currying10 = currying(10);
- クロージャによって、内部の関数が一つ目の引数を保持するため、このようなことができる
- ちなみに、次のようにも呼び出せる
別の呼び方
currying(2)(5);
- アロー関数を用いる場合は次のようになる
アロー関数を用いたカリー化の例
const currying = x => y => x + y;
関数の合成
- 関数型プログラミングでは、小さな関数(純粋関数であるという条件付き)を定義し、それらの関数を合成してプログラミングをする
簡素な関数の合成の例
const compose = (f1, f2) => x => f1(f2(x));
this
-
this
は、呼び出し元によって動的に参照先が変わる。ゆえに、関数の定義だけを見てthisの値が何かを決定できない - 基本的な参照先はベースオブジェクト(メソッドを呼ぶ際に、そのメソッドのドット演算子またはブラケット演算子のひとつ左にあるオブジェクトのこと)となる
- ただし、アロー関数内で定義された関数やメソッドにおけるthisがどの値を参照するかは関数の定義時に決まる
- アロー関数内のthisの参照は、外側のスコープへと探索していき、見つかったところのthisを示す
- また、
Function.prototype.bind()
によって、引数に指定したオブジェクトをthis
が参照するようにできる
20240811 コメントにより教示いただいた内容を元に追記 - クラスにおいて、
this
は、new
によって生成されたインスタンスを指す -
constructor
関数におけるthis
は、インスタンスを示すオブジェクトである
参考文献