JavaScript參考型別-函數,javascript引用函數
Function類型是ECMAScript參考型別中的一種,它就是我們熟悉的函數。有意思的是,在ECMAScript中,函數實際上是對象。
每個函數都是Function類型的執行個體,而且都與其他參考型別一樣具有屬性和方法。
由於函數是對象,因此函數名實際上就是指向這個函數對象的指標,不會與某個函數綁定。
定義函數的三種方式:
1.使用函式宣告文法。
function sum(num1,num2){ return num1+num2;}
2.使用函數運算式定義。
var sum = function(num1,num2){ return num1+num2;};通過變數名稱sum即可引用這個函數,sum();
因為是使用運算式定義,所以別忘了運算式要以;結尾。
3.使用Function建構函式。Function建構函式接收任意數量的參數,並且把最後一個參數看成函數體。
但這種方式效能不好,已不推薦使用。
var sum = new Function("num1","num2","return num1+num2");
我們需要注意的是,函數名僅僅是指向這個函數對象的一個指標,也就是一個變數而已,一個函數可能會有多個名字,就像一個對象可以被多個指標引用一樣。
例如上面的sum變數,當我們要調用函數時,用函數加上圓括弧,sum(1,2);。而不帶括弧的函數名sum表示的是我們訪問這個函數指標,而不是調用函數。在當把函數作為值傳遞時要注意這點。
理解了函數名只是一個指標,那也就可以理解為什麼ECMAScript中沒有函數重載了,當我們寫了兩個同名的函數時,只不過是把這個函數名代表的指標指向了後寫的那個函數對象,執行的結果看上去就是前一個函數被後一個同名的函數替代了。
之前說到定義函數的兩種方式,函式宣告和函數運算式。它們在定義函數時作用是一樣的,但是在解析器在向執行環境(比如瀏覽器)載入我們的js代碼時,對這兩種函數定義的載入順序是不一樣的。
解析器會先讀取函式宣告,並使其在執行任何代碼前可以被訪問;至於函數運算式,則只有等到解析器執行到它所在的那行代碼時,才會被解釋然後執行。例如:
alert(sum(1,2)); //可以執行//雖然函式宣告寫在函數調用的後面function sum(num1,num2){ return num1+num2;}
但下面這樣就不行:
alert(sum(1,2)); //產生錯誤//函數運算式var sum = function(num1,num2){ return num1+num2;};
由於在ECMAScript中,函數名本身就是變數,所以函數也可以當做值來使用。也就是說,不僅可以像傳遞參數一樣把一個函數傳遞給另一個函數,而且可以將一個函數作為另一個函數的結果返回。
function callFunction(function,argument){ return function(argument);}function add(num){ return num + 100;}var result = callFunction(add,100); alert(result); //200
在函數的內部,有兩個特殊的對象:arguments和this。
arguments對象與數組類似,裡麵包含著傳入函數中的所有參數,可以使用數組的方括弧文法來訪問。ECMAScript函數不介意傳遞進來多少參數,也不在乎傳遞進來參數的類型,你可以定義一個接收兩個參數的函數,但使用時可以傳遞任意個參數,或者一個也不傳。因為對於ECMAScript函數來說,命名的參數只不過是為我們在函數體使用參數時提供了便利,它並不是必須的,在函數體內可以使用arguments對象來得到傳遞給函數的每一個參數。
此外,arguments對象還有一個callee屬性,該屬性是一個指標,指向擁有這個arguments對象的函數。
函數的另一個特殊對象是this,這個this的行為和Java中的this類型。this引用的是函資料以執行的環境對象。(當在全域範圍中調用某個函數時,this對象引用的就是window這個全域對象)。
window.color = "red";var o = {color : "yellow"};function sayColor(){ alert(this.color);}sayColor(); //redo.sayColor = sayColor;o.sayColor(); //yellow在sayColor函數調用之前,this的值並不確定。在全域環境中調用sayColor(),this的值就是window。當調用o.sayColor()時,this引用的就是對象o。
函數的屬性:length和prototype。
length屬性比較簡單,它表示函數希望接收的具名引數的個數,就是定義函數時定義的參數的個數。
prototype屬性,就是函數對象得到原型屬性,這個在介紹對象的時候介紹過。這裡不再展開。
函數的方法:
每個函數都包含兩個非繼承而來的方法:apply()和call()。
這兩個方法的用途都是在特定的範圍中調用函數,實際上也就是用來設定函數體內this對象值。
這兩個方法的區別僅僅在於接收參數的方式不同,當不給函數傳遞參數的時候,使用哪個方法都無所謂。
window.color = "red";var o = {color : "yellow"};function sayColor(){ alert(this.color);}sayColor.apply(o); //yellowsayColor.call(o); //yellowsayColor(); //redsayColor.call(window); //red