全局變量名、局部變量名和形參名沖突時,覆蓋情況


以前錯誤的認為,全局變量名、局部變量名和形參名相同時,全局變量(也就是外部變量)被形參覆蓋,形參被局部變量覆蓋。

今天發現這樣理解並不對。比如

function foo(num){
  var num;
  console.log(num);  
}
foo(1)   //  1

//如果錯誤的理解為局部變量會覆蓋形參的話,會認為會輸出undefined

那事實是什么呢。實際上變量名沖突分兩種,一種是函數外的變量和函數里的局部變量的沖突,一種是函數內部的沖突。

第一種沖突,我把它理解為是作用域鏈的上游(最上游是全局對象的命名空間)會被下游函數的局部變量覆蓋。

其實我覺得這就是一種繼承關系,好比原型鏈里離目標對象近的新的方法覆蓋遠的舊的方法,甚至是好比HTML/CSS里字體、顏色等屬性的繼承。

只不過這里繼承的是一個上下文環境。

它們都有一個特點,自己有,用自己的;自己沒有,用父級的;父級沒有,再逐級向上。

//和HTML/CSS屬性繼承不同的是,JS作用域鏈還涉及變量/函數聲明

//簡單說,就是子元素一旦聲明了變量,不管有沒有賦值,都算做是有自己的了
//也就不會操作到父級了

var b;
function foo2() {
    console.log(b);
    var b;
}
foo2();//undefined

第二中是函數內部的沖突,即同一作用域內的沖突。

形參和局部變量其實就是同一作用域的。只不過JS里的形參省略了聲明(像是Java就需要和變量一樣做類型聲明)。

而在JS里有:同一作用域,重復申明但不賦值,不會對變量有影響

var a=1;
console.log(a);  //1
var a;
console.log(a);  //1

這也就解釋了,為什么局部變量申明但不賦值,不影響形參。

或許你會有我之前的另一種猜測,局部變量聲明但不賦值,不會覆蓋形參,但賦值了不是改變形參,而是覆蓋。

那我們再看看這個

var b;
function foo2(b) {
    var b=2;
    console.log(b);
    console.log(arguments[0]);
}
foo2(1);

//假如是局部變量名覆蓋形參名的話,那應該打印'2 1'
//而事實是'2 2'
//所以其實局部變量和形參沖突,就是重復定義個變量
//所以我覺得其實可以把形參理解為一個特殊的局部變量
//只不過它在函數定義時被申明,而且申明的var 被省略
function foo2(var b){
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM