無論你承不認可,任何人在社會環境中都會被潛在的分爲三六九等,而JavaScript中的函數就是一等公民。ajax
函數是以function關鍵字定義的一組用來執行特定功能的語句。定義函數有三種方式:函數聲明,函數表達式和構造函數。編程
函數聲明promise
function sum(num1,num2){ return num1+num2; }
函數表達式閉包
var sum=function(num1,num2){ return num1+num2; }
構造函數編程語言
var sum = new Function('num1', 'num2', 'console.log( num1 + num2)'); sum(2, 6);
構造函數的第三個參數是一個包括JavaScript語句的字符串。函數式編程
函數沒有重載函數
function addNumber(num){ return num+10; } function addNumber(count){ return count+20; } addNumber(10);//30
上面兩個函數名同樣,可是參數及計算方式不同,結果倒是執行第二個函數,由於後面的函數覆蓋了前面的函數。實際上與下面的代碼沒有區別:指針
var addNumber=function(num){ return num+10; }; addNumber=function(count){ return count+20; } addNumber(10);//30
能夠把函數名理解爲指針,同一個函數名指向同一個指針。code
函數聲明與函數表達式的區別
一、函數聲明是函數名跟在function後面,函數表達式是把一個函數賦值給一個變量;
二、函數聲明能夠在代碼的任何位置,調用不受限制(可訪問做用域),函數表達式必須在調用前定義。對象
console.log(addNumber(10));//20 function addNumber(num){ return num+10; }
console.log(addNumber(10));//Uncaught TypeError: addNumber is not a function var addNumber=function(num){ return num+10; };
再看一段代碼
function addNumber(num){ return num+10; } var addAnotherNumber=function addNumber(count){ return count+20; } console.log(addAnotherNumber.name);//addNumber
函數表達式不必定是匿名函數,定之後函數表達式的函數名是function後面的函數名。
重點注意:全部函數的參數都是按值傳遞
也就是說,把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。基本類型值的傳遞如同基本類型變量的複製同樣,而引用類型值的傳遞,則如同引用類型變量的複製同樣。
要理解上面這段話有點費勁。既然是複製,不是基本類型複製後互不影響,引用類型複製後會互相影響嗎,爲何是按值傳遞不是按引用傳遞?
在函數傳遞一個基本類型參數時,被傳遞的值會複製給函數內一個局部變量(arguments中的一個),傳遞一個引用類型的值時,會把該引用類型的指針地址複製給函數內一個局部變量,當局部變量發生變化時會反映在函數的外部。舉個例子:
函數參數傳遞一個數字,函數內部修改後
function addNumber(num){ num=num+10; console.log(num);//20 } var num=10; addNumber(num); console.log(num);//10
若是傳遞的是一個object,在函數內部修改對象屬性時,外部對象也發生變化了。
function setName(obj){ obj.name="李四" console.log(obj.name);//李四 } var obj={ name:"張三" }; setName(obj); console.log(obj);//obj.name="李四"
這不是與上面說的還值傳遞自相矛盾?咱們修改幾行代碼再看:
function setName(obj){ obj.name="李四" obj=new Object(); obj.name="王麻子"; console.log(obj.name);//王麻子 } var obj={ name:"張三" }; setName(obj); console.log(obj);//obj.name="李四"
這段代碼與上面的區別是obj傳遞給函數後,其屬性name被從新賦值,建立一個新對象賦值給obj,再修改obj.name。若是obj是按引用傳遞,那麼修改obj後應該也反映到函數外部,但原始引用並無發生變化。緣由是在函數內部重寫obj後實際上建立了一個新的對象引用,該變量引用是局部變量,函數執行完後即被銷燬。
總之,函數參數都是局部變量。
回到主題,JavaScript函數爲何是一等公民?
在編程語言中,一等公民有幾個條件:能夠做爲函數參數,能夠做爲函數返回值,能夠賦值給變量。
按照上面的條件,其實JavaScript中的數據均可以認爲是一等公民~
不管是基礎數據類型仍是引用類型都是知足上面條件的。通常說JavaScript函數是一等公民其實是相對其它編程語言而言,由於並非全部的編程語言中函數都能知足上述條件。
下面具體介紹下JavaScript中函數是如何知足上述三個條件的。
實際上就是咱們常常說的函數回調。舉個例子:
element.addEventListener(event,eventHandler,useCapture)
其中eventHandler就是做爲函數參數,元素監聽到對應事件後進行調用。這種狀況在JavaScript中很是常見。好比ajax,promise等等。
好比閉包:
function getName(){ var name="jack"; return function(){ return name; } } var getNameFun=getName(); var name=getNameFun(); console.log(name);//'jack'
正常狀況下函數外部是沒法訪問函數內部變量的,可是經過返回一個引用函數內部變量的函數就能夠實現,也就是咱們常說的閉包。
var getTime=function(){ console.log(new Date().getTime()); } setInterval(getTime,1000);
將函數做爲變量賦值給變量getTime,而後做爲參數傳遞給setTimeInterval。
函數做爲一等公民是函數式編程的基礎。高階函數就是將函數做爲參數的函數,React中的高階組件也能夠理解是高階函數。