下面是函數聲明的例子:數組
function factorial(n) { if (n<=1) return 1; return n*factorial(n-1); }
函數聲明語句一般出如今JS代碼的最頂層,也能夠嵌套在其餘函數體內。但在嵌套時,函數聲明只能出如今所嵌套函數的頂部。也就是說,函數定義不能出如今if語句、while循環或其餘任何語句中,正是因爲函數聲明位置的這種限制,ES標準規範並無將函數聲明歸類爲真正的語句。app
儘管函數聲明語句和函數定義表達式包含相同的函數名,但兩者仍然不一樣。兩種方式都建立了新的函數對象,但函數聲明語句中的函數名是一個變量名,變量指向函數對象。和經過var聲明變量同樣,函數定義語句中的函數被顯式地「提早」到了腳本或函數的頂部。所以它們在整個腳本和函數內都是可見的。使用var的話,只有變量聲明提早了------------變量的初始化代碼仍然在原來的位置。然而使用函數聲明語句的話,函數名稱和函數體均提早;腳本中的全部函數和函數中全部嵌套的函數都會在當前上下文中其餘代碼以前聲明。也就是說,能夠在聲明一個js函數以前調用它。函數
構成函數主體的JS代碼在定義之時並不會執行,只有調用該函數時,它們纔會執行。有4中方式來調用JS函數:做爲函數、做爲方法、做爲構造函數、經過它們的call()和apply()方法簡介調用。this
函數調用------------ 對於普通的函數調用,函數的返回值成爲調用表達式的值,若是該函數返回是由於解釋器到達結尾,返回值就是undefined。根據ES3和非嚴格的ES5對函數調用的規定,調用上下文(this的值)是全局對象。然而,在嚴格模式下,調用上下文則是undefined。以函數形式調用的函數一般不使用this關鍵字。不過,"this"能夠用來判斷當前是不是嚴格模式。
spa
var strict = (function(){return !this}());
方法調用--------------對方法調用的函數和返回值的處理,和上面描述的普通函數調用徹底一致。可是,方法調用和函數調用有一個重要的區別。即:調用上下文。函數體可使用關鍵字this引用該對象。和變量不一樣,關鍵字this沒有做用域的限制,嵌套的函數不會從它的函數中繼承this。若是嵌套函數做爲函數調用,其this值不是全局對象(非嚴格模式下)就是undefined(嚴格模式下)。例如:prototype
var o = { m: function() { var self = this; console.log(this == o); //輸出true,this就是這個對象o f(); function f() { console.log(this ===o) //false,this的值是全局對象或undefined console.log(self === o) //true:self值外部函數的this值 } } o.m();
4)構造函數的調用code
構造函數調用建立一個新的空對象,這個對象繼承自構造函數的prototype屬性。構造函數試圖初始化這個新建立的對象,並將這個對象做爲其調用上下文,所以構造函數可使用this關鍵字來引用這個新建立的對象。注意,儘管構造函數看起來像一個方法調用,它依然會使用這個新對象做爲調用上下文。也就是說,在表達式new o.m()中,調用上下文並非o。構造函數一般不使用return關鍵字,它們一般初始化新對象,當構造函數的函數體執行完畢時,它會顯式返回。在這種狀況下,構造函數調用表達式的計算結果就是這個新對象的值。然而若是構造函數顯式地使用return語句返回一個對象,那麼調用表達式的值就是這個對象。若是構造函數使用return語句但沒有指定返回值,或者返回一個原始值,那麼這時將忽略返回值,同時使用這個新對象做爲調用結果。對象
5) 間接調用
繼承
JS中函數也是對象,和其餘JS對象沒什麼兩樣。任何函數能夠做爲任何對象的方法來調用,哪怕這個函數不是那個對象的方法。咱們能夠將call()和apply()看做是某個對象的方法,經過調用方法的形式來間接調用函數。call()和apply()的第一個實參是要調用函數的母對象,它是調用上下文,在函數體內經過this來得到它的引用。要想以對象o的方法來調用函數f()。能夠這樣使用:
作用域
f.call(o); f.apply(o);
每行代碼和下面代碼的功能相似(假設對象o中預先不存在名爲m的屬性)。
o.m = f; o.m(); delete o.m;
在ES5嚴格模式下,call()和apply()的第一個實參都會變爲this的值,哪怕傳入的實參數原始值甚至是null或undefined。在ES3和非嚴格模式ES5中,傳入的null和undefined都會被全局對象代替,而其餘原始值則會被相應的包裝對象所代替。
對於call()來講,第一個調用上下文實參以後的全部實參就是要傳入待調用函數的值。好比,以對象o的方法的形式調用函數f(),並傳入兩個參數,可使用這樣的代碼:
f.call(o,1,2)
apply()方法和call()相似,但傳入實參的形式和call()有所不一樣,它的實參都放入一個數組當中:
f.apply(o,[1 2]);
若是一個函數的實參能夠是任意數量,給apply()傳入的參數數組能夠是任意長度的。好比,爲了找出數組中最大的數值元素,調用Math.max()方法的時候能夠給apply()傳入一個包含任意個元素的數組:
var biggest = Math.max.apply(Math, array_of_numbers);