JavaScript 的独特功能之一是“函数是对象,可以像任何对象一样被传递” [1]。
当 Eich 先生开始创建这种语言时,他为什么决定这样做?与 Java 等语言中通常的 OOP 风格相比,它有何优势?他是否有先例,或者这在当时是一个完全独特的想法?
JavaScript 的独特功能之一是“函数是对象,可以像任何对象一样被传递” [1]。
当 Eich 先生开始创建这种语言时,他为什么决定这样做?与 Java 等语言中通常的 OOP 风格相比,它有何优势?他是否有先例,或者这在当时是一个完全独特的想法?
当然不是他发明的,一流的功能从 60 年代就已经存在。
它赋予您的能力是编写所谓的高级函数——将其他函数作为参数的函数。这是函数式编程的基石。例如,Array.map
是一个将另一个函数作为输入的函数,允许强大的构造。
面向对象的编程是后来开发的,并且更多地关注耦合/分离数据和行为。这通常以容易推理代码为代价(在口语和数学意义上)。许多 OO 语言(Java、C#)现在正在添加这些函数式编程元素(即 lambdas)。
考虑用 Java 之类的语言实现Array.map
,Array.reduce
的复杂性。Array.filter
每次你想使用它时,你必须创建一个特殊的匿名内部类的实例,只是为了实现算法调用所需的函数。在 JavaScript 中,函数就像其他所有东西一样只是对象,所以你可以只传递一个,从而产生更简洁和自然的语法。
@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/Scheme 根源的结果(它的原型继承模型取自 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']
}