JavaScript之函數爲何是一等公民

無論你承不認可,任何人在社會環境中都會被潛在的分爲三六九等,而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中的高階組件也能夠理解是高階函數。

相關文章
相關標籤/搜索