請看以下兩個函數:
function a(){alert("a")}
var b = function(){alert("b")}
它們倆有何不同呢?翻開書,作者會告訴我們,前者為函式宣告,後者為函數運算式。函式宣告作為一種聲明,當然會在先行編譯階級有所動作(聲明提前),而函數運算式則不會。另一個區別是,函式宣告不能直接加一對括弧讓它們執行。第三個區別,運算式還可以繼續細分,運算式是由常量,變數,操作符,函數等組合而成,計算以後返回一個結果值,至少也會返回一個undefined。
function a (){ alert("a") }();//報錯
var b = function(){ alert("b") }();
(function foo(){}); // 運算式:注意它被包含在分組操作符中 var bar = function foo(){}; // 運算式,因為它是賦值運算式的一部分 new function bar(){}; // 運算式,因為它是New運算式的一部分
給 function 外套一對括弧(分組操作符)就不報錯了,括弧是運算式,是運算式就有傳回值,所以可以在後面加一對括弧讓它們執行,再看
(function a (){ alert("a") })();//沒有問題
<br /> (function a (){<br /> alert("a")<br /> })();//沒有問題<br />
運行代碼
另外,我們知道,函數名的作用就是用來引用的,現在沒用了,我們是不是可以把它去掉呢?
(function (){ alert(arguments.callee) })();//彈出自身
<br /> (function (){<br /> alert(arguments.callee)<br /> })();//彈出自身<br />
運行代碼
知道這個,我們就可以方便地遞迴自身了。如弄一個深拷貝函數
var deepExtend = function(destination, source) { for (var property in source) { if (source[property] && source[property].constructor && source[property].constructor === Object) { destination[property] = destination[property] || {}; arguments.callee(destination[property], source[property]); } else { destination[property] = source[property]; } } return destination;};
另外,從另一方便也啟法了我們如何兼價地批量生產各種各樣的自動執行函數。因為把函數轉換為運算式的方法並不一定要靠分組操作符,我們還可以用void操作符,~操作符,!操作符……
void function(){ alert("司徒正美");}()
0, function(){ alert("司徒正美");}();
-function(){ alert("司徒正美");}();
+function(){ alert("司徒正美");}();
!function(){ alert("司徒正美");}();
~function(){ alert("司徒正美");}();
typeof function(){ alert("司徒正美");}();