JavaScriptのユニークな機能の1つは、「関数はオブジェクトであり、他のオブジェクトと同じように渡すことができる」ということです[1]。
アイヒ氏が言語を作り始めたとき、なぜ彼はこれをすることに決めたのですか?Javaのような言語の通常のOOPスタイルと比較してどのように有利ですか?彼には前例がありましたか、それとも当時は完全にユニークなアイデアでしたか?
JavaScriptのユニークな機能の1つは、「関数はオブジェクトであり、他のオブジェクトと同じように渡すことができる」ということです[1]。
アイヒ氏が言語を作り始めたとき、なぜ彼はこれをすることに決めたのですか?Javaのような言語の通常のOOPスタイルと比較してどのように有利ですか?彼には前例がありましたか、それとも当時は完全にユニークなアイデアでしたか?
確かに彼はそれを発明しませんでした、一流の機能は60年代から存在していました。
それがあなたに与える力は、いわゆる上位クラスの関数、つまり他の関数を引数として取る関数を書くことです。これが関数型プログラミングの要です。たとえば、Array.map
は別の関数を入力として受け取る関数であり、強力な構造を可能にします。
オブジェクト指向プログラミングは後で開発され、データと動作の結合/分離に重点を置いています。これは多くの場合、コードについて簡単に推論することを犠牲にして行われます(口語的および数学的な意味の両方で)。多くのオブジェクト指向言語(Java、C#)は、関数型プログラミングのこれらの要素(つまり、ラムダ)を追加しています。
Javaのような言語での実装Array.map
の複雑さを考慮してください。これを使用するたびに、アルゴリズムの呼び出しに必要な関数を実装するためだけに、特別な匿名内部クラスのインスタンスを作成する必要があります。JavaScriptでは、関数は他のすべてと同じようにオブジェクトであるため、1つを渡すだけで、はるかに簡潔で自然な構文になります。Array.reduce
Array.filter
@OrangeDogは鼻にそれを持っています。この回答を書いているのは、関数、配列、および再帰のみを使用して、すべての「従来の」命令フロー制御を実際に実装できることを指摘するためです(true==1およびfalse==0と仮定)。
function ifElse(cond, trueFunc, falseFunc) {
var paths = [falseFunc, trueFunc]
return paths[cond()]();
}
function whileTrue(cond, action) {
return ifElse(cond, whileTrue(cond, action), function() {});
}
function forLoop(initial, cond, increment, action) {
initial();
return whileTrue(cond, function() {
var actionValue = action();
increment();
return actionValue;
}
}
function first(array) { // or ``car``
return array[0];
}
function rest(array) { // or ``cdr``
return array.slice(1);
}
function each(array, action) {
action(first(array));
each(rest(array), action);
}
等々。これはJavascriptのLisp/Schemaルートの結果であり(プロトタイプの継承モデルはSelfから取得され、構文はC / Javaから取得されました)、変更を加えることなく新しいフロー制御メカニズムを簡単に定義できるため、非常に強力です。言語自体、たとえば:
function categorizer(array, categorizer) {
var categories = {};
array.forEach(function(value, index, array) {
var category = categorizer(value, index, array);
ifElse(function() {
return categories[category] instanceof Array ? 1 : 0;
}, function() {
categories[category].push(value);
}, function() {
categories[category] = [value];
});
});
return categories;
}
これcategorizer
で、配列をオブジェクト内のラベル付き配列のセットに分割する方法を定義する関数を使用できるようになりました。これは、次のような他の場所で使用できます。
categorize(['foo', 'bar', 'baz'], function(value) {
return value.charAt(0);
});
// Produces the following:
{
f: ['foo'],
b: ['bar', 'baz']
}