函數表達式中,函數名稱在函數體內是只讀的


我們來看一個函數定義表達式:

var f=function a(){
    console.log(arguments.callee.name);//返回當前執行函數的 name
};
f();// a

可能有人覺得奇怪哈,很正常,因為一般我們不這么寫,要么不帶 a ,要么就直接用函數聲明語句了,不過這種寫法有它的優勢,用來遞歸的時候很方便,詳情 戳這里

這里主要來分析 a 的作用域的,上面的例子就為證明一點:

賦值給 f 的函數名稱是 a ,不是 f

關鍵是,這個 a 的作用域問題,我們在 f 執行完后,訪問 a:

image

報錯了,證明 a 不是全局變量,實際上書上也是這么說的:

image

測試下,邏輯上沒有問題:

image

不過我們不僅於此,我們在函數內給 a 重新賦值:

var f = function a() {
    a = 3;
    console.log(a);
};
f();

返回的是函數本身,說明賦值失敗了:

image

嚴格模式下,報錯,字面理解就是賦值給了常量(注意 , ES6 新增了常量 const,對於常量是不能重復賦值的):

image

這說明:

函數定義表達式中帶函數名稱的,函數名稱只能作為常量在函數體內訪問,不可以被重新賦值的,非嚴格模式下靜默失敗,嚴格模式下報錯;

既然知道了這個,如果在函數體內依然要給 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 引擎 把里面的函數聲明語句當成了表達式,那么這種情況下,這個效果不就等價於 帶名稱的函數定義表達式么?這個時候,函數名稱應該也是局部變量且只能在函數內部訪問,不可修改;

文檔上是這么說的:

參考資料:

JavaScript權威指南-第6版

文檔

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


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com