變數範圍
“一個變數的範圍表示這個變數存在的上下文。它指定了你可以訪問哪些變數以及你是否有許可權訪問某個變數。”
變數範圍分為局部範圍和全域範圍。
局部變數(處於函數層級的範圍)
不像其他對面對象的程式設計語言(比方說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文檔)。
每一個在函數外部聲明或者定義的變數都是一個全域對象,所以這個變數可以在任何地方被使用,例如:
複製代碼 代碼如下:
// 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關鍵字,那麼他自動加入到全域範圍中。
複製代碼 代碼如下:
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
最後一點, 在strict 模式下,如果沒有先聲明變數就給變數賦值將會報錯!