「Functions As First-Class Objects In JavaScript, functions are first-class objects. They can be stored in variables, passed into other functions as arguments, passed out of functions as return values, and constructed at run-time. These features provide a great deal of flexibility and expressiveness when dealing with functions.As you will see throughout the book, these features are the foundation around which you will build a classically object-oriented framework.」
"In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens."顯然,對於函數是一等「對象」的說法,自己就是源於程序自己的,也就是說當一個編程語言自己就是把函數當成一等公民的時候,那麼咱們就稱呼這個語言擁有「first-class function」,咋一看,這尼瑪不就等於沒說麼?其實否則,間接地,它是在告訴咱們:在不一樣編程語言裏面,函數(對象)是處於不一樣地位的,怎麼去理解這句話,固然要繼續閱讀下去,咱們繼續看原文:
"Specifically, this means that the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures. [1] [2] Some programming language theorists require support for anonymous functions as well. [3] In languages with first-class functions, the names of functions do not have any special status, they are treated like ordinary variables with a function type. [4] The term was coined by Christopher Strachey in the context of 「functions as first-class citizens」 in the mid-1960s. [5]"從上面語句中,咱們大致能夠得到這樣的信息:
"A simple example of a higher-ordered function is the map function, which takes as its arguments a function and a list, and returns the list formed by applying the function to each member of the list. For a language to support map, it must support passing a function as an argument."頗有意思的函數,就好像C語言的main函數似的(固然有本質的區別),它好像有一種把全部函數集合在一塊兒,再綜合調用的意思,可是它實現的功能是遠遠強大於C的main函數的,這裏我也不便多說,須要本身去體會。
1 void map(int (*f)(int), int x[], size_t n) { 2 for (int i = 0; i < n; i++) 3 x[i] = (*f)(x[i]); 4 }
注意:C語言採用指針類型來實現。javascript
1 int f(int x) { 2 return 3 * x + 1; 3 } 4 int main() { 5 int l[] = {1, 2, 3, 4, 5}; 6 map(f, l, 5); 7 }
1 typedef struct { 2 int (*f)(int, int, int); 3 int *a; 4 int *b; 5 } closure_t; 6 void map(closure_t *closure, int x[], size_t n) { 7 for (int i = 0; i < n; ++i) 8 x[i] = (*closure->f)(*closure->a, *closure->b, x[i]); 9 } 10 int f(int a, int b, int x) { 11 return a * x + b; 12 } 13 void main() { 14 int l[] = {1, 2, 3, 4, 5}; 15 int a = 3; 16 int b = 1; 17 closure_t closure = {f, &a, &b}; 18 map(&closure, l, 5); 19 }
「Also note that the由此本質上,C語言是不支持內嵌函數的,然而在 C語言中,存在一些模擬閉包的庫,支持 回調函數callback的庫有時在註冊時須要兩個參數:一個函數指針,一個獨立的map
is now specialized to functions referring to twoint
s outside of their environment. This can be set up more generally, but requires more boilerplate code. Iff
would have been a nested function we would still have run into the same problem and this is the reason they are not supported in C.」
void*
指針用以保存用戶數據。這樣的作法容許回調函數恢復其調用時的狀態。這樣的慣用法在功能上相似於閉包,但語法上有所不一樣。
"When returning a function, we are in fact returning its closure. In the C example any local variables captured by the closure will go out of scope once we return from the function that builds the closure. Forcing the closure at a later point will result in undefined behaviour, possibly corrupting the stack. This is known as the upwards funarg problem."
「當返回一個函數自己時,咱們其實是返回了這個閉包(由於閉包就是一種函數),在這個C語言示例裏面,一旦咱們返回那些閉包,那麼那些閉包所約束的局部變量將會溢出它的做用域,強行返回一個‘later point’將會致使一個未定義行爲,頗有可能就是堆棧溢出,這就是所謂的‘ upwards funarg problem「這是我對這句話的拙劣的翻譯,拋開各類專業性的問題,顯然它是在告訴咱們C語言對這種機制的實現是不完善的。換一個角度來講,C語言或許在構造的時候就天生不是實現閉包的最佳語言,它是不太適合進行函數式編程模式的。 這裏,又有來自於wiki的一個總結:
"The C family allowed both passing functions as arguments and returning them as results, but avoided any problems by not supporting nested functions. (The gcc compiler does allows them as an extension.) As the usefulness of returning functions primarily lies in the ability to return nested functions that have captured non-local variables, instead of top-level functions, these language are generally not considered to have first-class functions."這裏面大體的意思是這樣的,C語言家族裏面,它是能夠實現函數的參數傳入和函數類型的返回(大體都是用指針來模擬實現的),可是因爲內嵌函數的不支持性(除了gcc編譯器對其的擴展,ps:多是一個特例吧),而且針對返回的函數必定要是有意義的這一層面來講,返回內嵌函數顯然是意義斐然的,因此C語言是不具備一等函數(first-class function)的,這裏我能夠補充一個javacript的例子:
1 var outer = function(){ 2 var innerNum = 123; 3 return function(){ 4 console.log(++innerNum); 5 }; 6 }(); 7 outer();
Language | Higher-order functions | Non-local variables | Partial application | Notes | ||||
---|---|---|---|---|---|---|---|---|
Arguments | Results | Nested functions | Anonymous functions | Closures | ||||
Algol family | ALGOL 60 | Yes | No | Yes | No | No | No | Have function types. |
ALGOL 68 | Yes | Yes[9] | Yes | Yes | No | No | ||
Pascal | Yes | No | Yes | No | No | No | ||
Oberon | Yes | Non-nested only | Yes | No | No | No | ||
C family | C | Yes | Yes | No | No | No | No | Has function pointers. |
C++ | Yes | Yes | No | C++11[10] | C++11[10] | No | Has function pointers, function objects. (Also, see below.) | |
C# | Yes | Yes | No | 2.0 / 3.0 | 2.0 | No | Has delegates (2.0) and lambda expressions (3.0). | |
Objective-C | Yes | Yes | No | 2.0 + Blocks[11] | 2.0 + Blocks | No | Has function pointers. | |
Java | Partial | Partial | No | No | 8 | No | Has anonymous inner classes. | |
Functional languages | Lisp | Syntax | Syntax | Yes | Yes | Common Lisp | No | (see below) |
Scheme | Yes | Yes | Yes | Yes | Yes | SRFI 26[12] | ||
Clojure | Yes | Yes | Yes | Yes | Yes | Yes | ||
ML | Yes | Yes | Yes | Yes | Yes | Yes | ||
Haskell | Yes | Yes | Yes | Yes | Yes | Yes | ||
Scala | Yes | Yes | Yes | Yes | Yes | Yes | ||
Scripting languages | JavaScript | Yes | Yes | Yes | Yes | Yes | ECMAScript 5 | Partial application possible with user-land code on ES3 [13] |
PHP | Yes | Yes | Unscoped | 5.3 | 5.3 | No | (see below) | |
Perl | Yes | Yes | 6 | Yes | Yes | 6[14] | ||
Python | Yes | Yes | Yes | Partial | Yes | 2.5[15] | (see below) | |
Ruby | Syntax | Syntax | Unscoped | Yes | Yes | 1.9 | (see below) | |
Other languages | Mathematica | Yes | Yes | Yes | Yes | Yes | No | |
Smalltalk | Yes | Yes | Yes | Yes | Yes | Partial | Partial application possible through library. | |
Fortran | Yes | Yes | Yes | No | No | No |