簡體   English   中英

JavaScript 變量提升示例

[英]JavaScript variable hoisting example

我有一個關於 JavaScript 中變量提升的問題。

考慮以下示例:

var myName = "Richard"; // Variable assignment (initialization)
​
​function myName () {
console.log ("Rich");
}
​
console.log(typeof myName); // string 

我實際上很困惑為什么typeof myName作為string返回。

根據我的理解,該示例將按以下方式處理;

  1. 首先函數聲明( function myName () )將被提升到頂部,然后
  2. JS 解釋器會讀取var myName = "Richard"這一行(因為函數聲明優先於變量聲明)。 但是,由於已經存在名為“myName”的屬性,因此該語句將被忽略。

因此typeof myName應該作為函數(而不是字符串)返回。

我的理解哪里不對?

JavaScript 有一個動態類型系統,即變量的類型可以隨時間改變。 基本上,您編寫的內容是正確的:首先,函數聲明會運行(在加載文件時),但隨后存儲在變量myName的函數被字符串覆蓋。

唯一被忽略的是對var的調用,因為變量實際上已經聲明了。

但是重新定義一個變量是完全有效的(這就是你在這里所做的,通過分配一個新值)。

最后,你的樣本不過是這樣的:

var x = 23;
x = 'foo';

這也將起作用, x將是'foo' ,它的類型將是string 與您的示例的唯一區別是,在您的示例中,涉及function類型的值。

除了其他答案之外,還應該注意的是,如果您以下列方式聲明您的函數:

var myName = function() {
  console.log('Rich');
}

或者干脆

myName = function(){
  console.log('Rich')
}

與“function myName . . .”語法相反,typeof myName 將返回“function”

2 年過去了,但也許它仍然與某人有關 您是對的,在解釋對象時確實如此:

  • 掃描函數聲明的上下文

    • 對於找到的每個函數,在變量對象中創建一個屬性
    • 如果函數名已經存在,引用指針值將被覆蓋
  • 掃描變量聲明的上下文

    • 對於找到的每個變量聲明,在變量對象中創建一個屬性,即變量名,並將值初始化為 undefined
    • 如果變量對象中已經存在變量名,則什么都不做,繼續掃描

但是,對於全局范圍而言,情況似乎並非如此。 即,當我定義一個對象時,輸出與它應該完全一樣,當我在全局范圍內定義相同時,它不是......仍然試圖圍繞這個

由於Hoisting你的變量和函數定義被移到頂部,所以你有:

var myName;
// moved to top
function myName () {
  console.log ("Rich");
}

// next your code
myName = "Richard";

console.log(typeof myName); // string 

如果你像這樣重寫你的代碼:

var myName = "Richard"; // Variable assignment (initialization)
​
myName = ​function () {  // Variable redefinition
  console.log ("Rich");
}
​
console.log(typeof myName); // function

你的myName變量現在是一個函數,因為只有myName變量被hoisted

var myName;

myName = "Richard";     // Variable assignment (initialization)
myName = ​function () {  // Variable redefinition
  console.log ("Rich");
}
​
console.log(typeof myName); // outputs 'function'

“提升”的想法是一種理解正在發生的事情的糟糕方式。 換句話說,在我看來,“吊裝”是對吊裝的不好解釋。

真正發生的不是“提升”。 真正發生的是javascript分兩個階段執行代碼:編譯階段和評估階段。 javascript 社區稱此為“提升”的症狀,但大多數人無法理解為什么要提升提升,因為他們認為 javascript 解釋器具有稱為“提升”的此功能(他們沒有)。

實際發生的事情比起吊的想法更容易解釋。 規則是:

  1. Javascript 總是自上而下地解析代碼。 它從不重新排序代碼(從不提升)。

  2. 執行有兩個階段:編譯和評估。

  3. 所有聲明都在編譯階段處理,在編譯階段不會評估任何表達式(因為“評估”事情是在評估階段完成的)。

  4. 在求值階段處理所有表達式和任何其他需要求值的內容。

記住規則 1,所有解析都是自上而下完成的,沒有回溯,沒有提升。

讓我們以您的示例為例,並通過牢記 javascript 的編譯和評估階段來嘗試理解它:

    var myName = "Richard"; // Variable assignment (initialization)
​    
 ​   function myName () {
       console.log ("Rich");
    }

​    console.log(typeof myName); // string 
  1. 在編譯階段,解釋器會看到你聲明了一個變量。 它為此變量分配一塊內存區域,並為其分配undefined值。

  2. 在編譯階段,解釋器會看到你聲明了一個函數。 它還注意到函數名掩蓋了變量名。 因此它創建了一個函數“myName”(這意味着此時變量myName指向該函數)。

  3. 編譯階段結束。 現在我們進入評估階段。

  4. 在評估階段,解釋器會看到您為myName分配一個字符串。

  5. 當我們到達函數聲明時,沒有什么要評估的,因為聲明是在編譯階段處理的。

  6. 在評估階段,解釋器會看到你 console.logging typeof myName 由於分配給它的最后一個東西是一個字符串,它打印“字符串”。

請注意,如果您刪除字符串賦值,則myName將是 typeof "function"。 那是因為在這種情況下,分配給它的最后一件事是聲明的函數。

有關由兩個執行階段引起的其他微妙之處,請參閱此相關問題: JavaScript 函數聲明和評估順序

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM