JS函數名與變量名重名的問題

JS函數名與變量名重名的問題

由於JavaScript的預編譯會導致變量聲明提升,聲明式函數整體提升,因此當函數名與變量名重名的時候將會產生問題。

變量以及變量表達式(包括函數的表達式聲明)在預編譯階段都只是聲明提升,而沒有賦值,值都爲undefined。

而聲明式函數在預編譯階段將會整體提升。

而在編譯過程中,提升也是有順序的:參數 > 函數 > 變量

因此函數與變量的預編譯遵循以下規則:

  1. 函數聲明置頂;
  2. 變量聲明置頂;
  3. 遇到同名時,變量聲明比函數聲明更優先(置頂);
  4. 變量不會重複聲明;
  5. 直接變量聲明時賦值,在預編譯解析時,會拆成聲明和賦值2個部分,聲明會置頂,而賦值將保留在原來的位置;
  6. 聲明的提升只會提升到當前作用域下的頂層,而不會提升到作用域之外。
  7. 預編譯過程中形成的作用域鏈的查找順序是由裏向外,JS執行順序是自上往下的。
  8. 當函數被聲明在判斷語句內部時,JS會將函數聲明當成表達式(賦值聲明),即不會提升
//變量或變量表達式聲明提升
var a = 10;
//這相當於
var a;   //這就是發生在預編譯階段的變量的聲明提升,在這個階段變量只有聲明,而沒有賦值,爲undefined
a = 10;  //這是在執行階段,將會對變量賦值

//函數表達式
let fun  = function(){
    console.log('hello simon');
}
//這相當於
let fun; //這就是發生在預編譯階段的變量的聲明提升,在這個階段變量只有聲明,而沒有賦值,爲undefined
fun = function(){   //執行階段纔會進行定義
   console.log('hello simon'); 
}
//聲明式函數整體提升
var a = 10;
function fun(){
    var b = 11;
}
//這相當於
function fun(){
    var b; 
    b = 11;
}
var a;
a = 10;

題1

由於函數聲明是整體提升的,因此下面代碼中,a函數聲明在前,而變量a賦值在後,因此a是一個變量,而不是一個函數了,a執行出錯

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

//相當於
var a = function(){
    console.log(a);
};
a = 10;
a();  //將報錯,此時a是一個變量了

題2

預編譯過程中形成的作用域鏈的查找順序是由裏向外,JS執行順序是自上往下的。因此下面代碼中a = 1時,if的作用域中並不存在a變量,所以會將1賦值給全局中的a變量。

var  a = 0;
if(true){
    a = 1;  //作用域中不存在a變量,因此會通過作用域鏈向外查找,找到全局中的a變量,並將1賦值
    function a(){}  //這是函數聲明,相當於定義了一個函數a,並給其分配了內存
    a = 21;  //此時作用域中已經存在了a變量(a函數),因此該賦值將直接賦值給作用域中的a而不是全局的a
    console.log('裏面', a);  //21,由於作用域中存在a變量了,因此直接打印作用域中的a
}
console.log('外面', a);   //1,全局作用域中存在a變量,並賦值爲1,因此打印1

//相當於
var a;
a = 0;
if(true){
    a = 1;
    function a(){}  //由於函數是定義在判斷語句中,所以沒有聲明提升
    a = 21;
    console.log('裏面', a)  //21
}
console.log('外面', a);   //1

題3

函數會整體提升,因此b函數會被提升到全局作用域中的頂部,而a函數被提升到b函數作用域頂部。注意函數是自上而下執行的

var a = 1;
function b(){
    a = 10;
    return;
    function a(){
        console.log(a);
    }
}
b();
console.log(a);

//相當於
function b(){  //整體提升
    function a(){   //整體提升
        console.log(a);
    }
    a = 10;
    return;
}
var a;
a = 1;
b();  //執行b函數後,內部函數a會聲明,因此作用域內存在一個a變量(函數),a = 10會賦值給a函數,而不是全局中的a變量了
console.log(a);  //1  打印的是全局的a變量,內部的a變量無法獲取到
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章