javascript中的變量做用域以及變量提高

在javascript中, 理解變量的做用域以及變量提高是很是有必要的。這個看起來是否很簡單,但其實並非你想的那樣,還要一些重要的細節你須要理解。javascript

變量做用域

「一個變量的做用域表示這個變量存在的上下文。它指定了你能夠訪問哪些變量以及你是否有權限訪問某個變量。」html

變量做用域分爲局部做用域全局做用域。java

局部變量(處於函數級別的做用域)

不像其餘對面對象的編程語言(比方說C++,Java等等),javascript沒有塊級做用域(被花括號包圍的);當是,javascript有擁有函數級別的做用域,也就是說,在一個函數內定義的變量只能在函數內部訪問或者這個函數內部的函數訪問(閉包除外,這個咱們過幾天再寫個專題)。編程

函數級別做用域的一個例子:
瀏覽器

var name = "Richard";
 
function showName () {
    var name = "Jack"; // local variable; only accessible in this showName function
    console.log (name); // Jack
}
console.log (name); // Richard: the global variable

沒有塊級做用域:
閉包

var name = "Richard";
// the blocks in this if statement do not create a local context for the name variable
if (name) {
    name = "Jack"; // this name is the global name variable and it is being changed to "Jack" here
    console.log (name); // Jack: still the global variable
}
 
// Here, the name variable is the same global name variable, but it was changed in the if statement
console.log (name); // Jack
 
    不要忘記使用var關鍵字
    若是聲明一個變量的時候沒有使用var關鍵字,那麼這個變量將是一個全局變量!
// If you don't declare your local variables with the var keyword, they are part of the global scope
var name = "Michael Jackson";
 
function showCelebrityName () {
    console.log (name);
}
 
function showOrdinaryPersonName () {    
    name = "Johnny Evers";
    console.log (name);
}
showCelebrityName (); // Michael Jackson
 
// name is not a local variable, it simply changes the global name variable
showOrdinaryPersonName (); // Johnny Evers
 
// The global variable is now Johnny Evers, not the celebrity name anymore
showCelebrityName (); // Johnny Evers
 
// The solution is to declare your local variable with the var keyword
function showOrdinaryPersonName () {    
    var name = "Johnny Evers"; // Now name is always a local variable and it will not overwrite the global variable
    console.log (name);
}
    局部變量優先級大於全局變量
若是在全局做用域中什麼的變量在局部做用域中再次聲明,那麼在局部做用域中調用這個變量時,優先調用局部做用域中聲明的變量:
var name = "Paul";
 
function users () {
    // Here, the name variable is local and it takes precedence over the same name variable in the global scope
var name = "Jack";
 
// The search for name starts right here inside the function before it attempts to look outside the function in the global scope
console.log (name); 
}
 
users (); // Jack
 

全局變量

全部在函數外面聲明的變量都處於全局做用域中。在瀏覽器環境中,這個全局做用域就是咱們的Window對象(或者整個HTML文檔)。app

每個在函數外部聲明或者定義的變量都是一個全局對象,因此這個變量能夠在任何地方被使用,例如:編程語言

// name and sex is not in any function
var myName = "zhou";
var sex = "male";
 
//他們都處在window對象中
console.log(window.myName); //paul
console.log('sex' in window); //true

若是一個變量第一次初始化/聲明的時候沒有使用var關鍵字,那麼他自動加入到全局做用域中。ide

function showAge(){
  //age初始化時沒有使用var關鍵字,因此它是一個全局變量
  age = 20;
  console.log(age);
}
 
showAge();  //20
console.log(age); //由於age是全局變量,因此這裏輸出的也是20

setTimeout中的函數是在全局做用域中執行的函數

setTimeout中的函數所處在於全局做用域中,因此函數中使用this關鍵字時,這個this關鍵字指向的是全局對象(Window):

var Value1 = 200;
var Value2 = 20;
var myObj = {
  Value1 : 10,
  Value2 : 1,
  
  caleculatedIt: function(){
    setTimeout(function(){
      console.log(this.Value1 * this.Value2);
    }, 1000);
  }
}
 
myObj.caleculatedIt(); //4000
爲了不對全局做用域的污染, 因此通常狀況下咱們儘量少的聲明全局變量。 

 

變量提高(Variable Hoisting)

因此的變量聲明都會提高到函數的開頭(若是這個變量在這個函數裏面)或者全局做用域的開頭(若是這個變量是一個全局變量)。咱們來看一個例子:

function showName () {
console.log ("First Name: " + name);
var name = "Ford";
console.log ("Last Name: " + name);
}
 
showName (); 
// First Name: undefined
// Last Name: Ford
 
// The reason undefined prints first is because the local variable name was hoisted to the top of the function
// Which means it is this local variable that get calls the first time.
// This is how the code is actually processed by the JavaScript engine:
 
function showName () {
    var name; // name is hoisted (note that is undefined at this point, since the assignment happens below)
console.log ("First Name: " + name); // First Name: undefined
 
name = "Ford"; // name is assigned a value
 
// now name is Ford
console.log ("Last Name: " + name); // Last Name: Ford
}

函數聲明會覆蓋變量聲明

若是存在函數聲明和變量聲明(注意:僅僅是聲明,尚未被賦值),並且變量名跟函數名是相同的,那麼,它們都會被提示到外部做用域的開頭,可是,函數的優先級更高,因此變量的值會被函數覆蓋掉。

// Both the variable and the function are named myName
var myName;

function myName () {
console.log ("Rich");
}
 
// The function declaration overrides the variable name
console.log(typeof myName); // function

 

可是,若是這個變量或者函數其中是賦值了的,那麼另一個將沒法覆蓋它:

// But in this example, the variable assignment overrides the function declaration
var myName = "Richard"; // This is the variable assignment (initialization) that overrides the function declaration.
 
function myName () {
console.log ("Rich");
}
 
console.log(typeof myName); // string
 
最後一點, 在嚴格模式下,若是沒有先聲明變量就給變量賦值將會報錯!
相關文章
相關標籤/搜索