我們來看一個函數定義表達式:
var f=function a(){ console.log(arguments.callee.name);//返回當前執行函數的 name };
f();// a
可能有人覺得奇怪哈,很正常,因為一般我們不這么寫,要么不帶 a ,要么就直接用函數聲明語句了,不過這種寫法有它的優勢,用來遞歸的時候很方便,詳情 戳這里;
這里主要來分析 a 的作用域的,上面的例子就為證明一點:
賦值給 f 的函數名稱是 a ,不是 f
關鍵是,這個 a 的作用域問題,我們在 f 執行完后,訪問 a:
報錯了,證明 a 不是全局變量,實際上書上也是這么說的:
測試下,邏輯上沒有問題:
不過我們不僅於此,我們在函數內給 a 重新賦值:
var f = function a() { a = 3; console.log(a); }; f();
返回的是函數本身,說明賦值失敗了:
嚴格模式下,報錯,字面理解就是賦值給了常量(注意 , ES6 新增了常量 const,對於常量是不能重復賦值的):
這說明:
函數定義表達式中帶函數名稱的,函數名稱只能作為常量在函數體內訪問,不可以被重新賦值的,非嚴格模式下靜默失敗,嚴格模式下報錯;
既然知道了這個,如果在函數體內依然要給 a 賦值也不是不行,換成變量就可以了;
var f = function a() { var a = 3; console.log(a); }; f();//返回 3
當然這樣就不能繼續用 a 來訪問原來的函數了,雖然還有其他辦法,但是這樣修改明顯是不合適的,可讀性不好;
另外,在函數聲明語句中是可以的修改函數名稱,比如:
function a() { a = 3; console.log(a); } a();//3,a 變成 3
但是,放在 IIFE 中,又不行了;
(function a() { a = 3; console.log(a);//函數,修改失敗; })()
a;//error not defined;
當然,var 仍然是可行的,
(function a() { var a = 3; console.log(a);//3 成功 })()
對於 IIFE 中執行失敗的解釋,我猜測:
() 強制 js 引擎 把里面的函數聲明語句當成了表達式,那么這種情況下,這個效果不就等價於 帶名稱的函數定義表達式么?這個時候,函數名稱應該也是局部變量且只能在函數內部訪問,不可修改;
文檔上是這么說的:
參考資料:
https://stackoverflow.com/questions/24021489/variable-in-function-body-and-function-itself-have-the-same-name-javascript/24022076#24022076
https://stackoverflow.com/questions/15129504/why-are-anonymous-function-expressions-and-named-function-expressions-initialize
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。