JavaScript
中的函數使用function
關鍵字,後跟一組參數以及函數體。例如:函數
function foo(arg0, arg1,...,arg) {
...
}
var foo = function () {
...
};
(function () {
...
})();
複製代碼
在JavaScript
中有三種函數類型:函數聲明,函數表達式和函數構造器建立的函數。下面分別介紹這三種函數類型。工具
函數聲明由一系列的function
關鍵字組成,依次爲:post
例如:學習
function foo(arg0, arg1,...,arg) {
var a = 1;
console.log(a);
}
複製代碼
函數表達式和函數聲明很是類似,依次爲:ui
例如:spa
var foo = function () {
var b = 2;
console.log(b);
};
var foo = function bar() {
var b = 2;
console.log(b);
};
(function() {
var c = 3;
console.log(c);
})();
複製代碼
能夠經過Function
對象使用new
操做符建立一個構造函數。例如:debug
new Function('alert('hello'); alert('world');');
複製代碼
這裏重點學習函數聲明和函數表達式。建立函數的最經常使用的兩個方法是函數表達式和函數聲明。調試
函數聲明:code
function 函數名稱 (參數:可選){ 函數體 }cdn
函數表達式:
function 函數名稱(可選)(參數:可選){ 函數體 }
因此,建立一個函數若是不聲明函數名稱,它確定是表達式,可若是聲明瞭函數名稱的話,如何判斷是函數聲明仍是函數表達式呢?
區分函數聲明和表達式最簡單的方法是看 function
關鍵字出如今聲明中的位 置(不單單是一行代碼,而是整個聲明中的位置)。若是 function
是聲明中 的第一個詞,那麼就是一個函數聲明,不然就是一個函數表達式。或者這麼理解function foo(){}
是做爲賦值表達式的一部分的話,那它就是一個函數表達式,若是function foo(){}
被包含在一個函數體內,或者位於程序的最頂部的話,那它就是一個函數聲明。
例如:
function foo(){} // 聲明,由於它是程序的一部分
var bar = function foo(){}; // 表達式,由於它是賦值表達式的一部分
new function bar(){}; // 表達式,由於它是new表達式
(function(){
function bar(){} // 聲明,由於它是函數體的一部分
})();
(function foo(){}); // 表達式 包含在分組操做符內
複製代碼
對於函數表達式,最熟悉的場景就是回調,例如:
setTimeout(function(){
console.log("hello world!");
},1000);
複製代碼
這是一個匿名函數表達式,在平常開發和工具庫中這種模式很常見。可是它也有幾個缺點須要考慮。
例如:
具名函數
function foo(){
return bar();
}
function bar(){
return baz();
}
function baz(){
debugger;
}
foo(); //當調試器debugger的調用棧,棧中顯示了baz,bar,foo。
// 這是一個自執行的函數,函數內部執行自身,遞歸
function self() {
self();
}
複製代碼
匿名函數
function foo(){
return bar();
}
var bar = (function(){
return function(){
return baz();
};
})();
function baz(){
debugger;
}
foo();//當調試器debugger的調用棧,棧中顯示了baz,(anonymous),foo。
// 這是一個自執行的匿名函數,由於沒有標示名稱
// 必須使用arguments.callee屬性來執行本身
var self = function () {
arguments.callee(); //在嚴格模式下,ES5禁止使用 arguments.callee()。
};
複製代碼
給函數表達式指定一個函數名,不會影響其功能,反而是一個比較好的實現方式,例如:
setTimeout(function handle(){
console.log("hello world!");
},1000);
複製代碼
(function foo() {
var a = 1;
console.log(1);
})();
(function () { /* code */ } ()); // 推薦使用這個
(function () { /* code */ })(); // 可是這個也是能夠用的
複製代碼
因爲函數被包含在一對 ( ) 括號內部,所以成爲了一個表達式,經過在末尾加上另一個 ( ) 能夠當即執行這個函數,好比(function foo(){ .. })()
。第一個 ( ) 將函數變成表 達式,第二個 ( ) 執行了這個函數。這種模式也叫當即執行函數表達式(IIFE)。
除了( ) 括號外,還有不少其餘的方式也能讓一個函數變成函數表達式,例如:
//&&,異或,逗號等操做符
true && function () { /* code */ } ();
1, function () { /* code */ } ();
//一元操做符號
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
複製代碼
可是依然使用( ) 括號,括號內部原本指望的就是函數表達式,主要是爲了方便開發人員閱讀。
IIFE一些常見應用,例如:
var a = 1;
(function ( global ) {
var a = 2;
console.log( a ); // 2
console.log( global.a ); // 1
})( window );
console.log( a ); // 1
複製代碼
var module = (function () {
var i = 0;
return {
get: function () {
return i;
},
set: function (val) {
i = val;
},
add: function () {
return ++i;
}
};
} ());
module.get(); // 0
module.set(1);
module.add(); // 1
module.i // undefined 由於i不是返回對象的屬性
複製代碼
這一節是對學習JavaScript做用域中的函數做用域的一個補充。這樣把瑣碎的知識串聯起來,更容易造成體系。