1

JavaScript的獨特功能之一是'功能是對象,可以像任何對象一樣傳遞'[1]通過將函數轉換爲JavaScript中的對象實現了什麼?

當艾希先生開始創建語言時,他爲什麼決定這麼做?與Java等語言中通常的OOP風格相比,它有什麼優勢?他有過先例,還是當時這是一個完全獨特的想法?

+1

給函數fi第一類的狀態並不是新的,js是單線程的,所以爲了確保它不會阻止UI,經常有很多事情使用回調異步執行,儘管這只是一種預感,在我看來,js是一種函數式語言。 – 2012-07-18 20:50:11

+1

我想象一下,如果函數不是對象,那麼編寫基於原型的OOP語言會遇到挑戰。 – kojiro 2012-07-18 20:53:57

+1

想一想,這個問題意味着函數的第一類和基於類的OOP之間存在關聯。 (我認爲這就是通常的OOP風格的意義。)在基於類的語言中,函數仍然可以是一流的。 – kojiro 2012-07-18 21:02:59

回答

4

當然他沒有發明它,first-class functions自60年代以來就已存在。

它給你的力量是編寫所謂的高級函數 - 將其他函數作爲參數的函數。這是函數式編程的基石。例如,Array.map是一個將另一個函數作爲輸入的函數,允許強大的構造。

面向對象的程序設計是在後來開發的,主要集中在耦合/分離數據和行爲。這通常是以代碼輕鬆推理爲代價的(無論是在口語還是數學意義上)。許多OO語言(Java,C#)現在都增加了函數式編程(即lambda)的這些元素。

考慮使用像Java這樣的語言實現Array.map,Array.reduce,Array.filter的複雜性。每次你想使用它時,你都必須創建一個特殊的匿名內部類的實例,僅僅是爲了實現算法調用所需的函數。在JavaScript中,函數只是其他所有對象的對象,所以您只需傳入一個對象,即可獲得更簡潔自然的語法。

2

@OrangeDog在鼻子上。我寫這個答案僅僅是爲了指出你實際上只能用函數,數組和遞歸實現所有的「經典」命令式流程控制(假設爲真== 1和假== 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'] 
} 
+0

你甚至可以用純函數做算術運算! https://github.com/MatrixFrog/church_js不是我會推薦它:一般來說,速度非常慢。但至少你不會得到任何奇怪的浮點錯誤:P – MatrixFrog 2012-07-20 15:51:21

相關問題