字面意思,作用域是指變量和函數的作用范圍,換言之,作用域決定了變量和函數的可見性和有效時間。javascript作用域是用函數來區分,與其他語言的大括號不同。
for (var i=0; i<5; i++){
var mystring = "平底斜";
console.log(i);
}
alert(mystring);//彈出"平底斜"
這段代碼在javascript中運行正常,在其他語言中就會報錯。這是因為javascript的作用域是基於函數,而不是大括號。
作用域分為全局作用域和局部作用域。
有三種情況會出現全局作用域:
1、最外層定義的變量和函數
var mystring = "平底斜";
function fun(){
alert("Hello World");
}
變量mystring和函數fun()擁有全局作用域,在任何位置都可以直接調用。
2、未定義的變量
function fun(){
var a=b=0;
mystring = "平底斜";
console.log(mystring);
}
fun();
alert(b);
變量mystring沒有使用var進行變量聲明,所以即使在函數內部也是全局變量。容易忽略的是變量b,看上去使用var進行了聲明,實際上只對變量a進行了聲明,等同於
function fun(){
var a=(b=0); //自右向左賦值
mystring = "平底斜";
console.log(mystring);
}
一個JS文件中應該盡可能少的出現全局變量,最佳實踐是使用var進行變量聲明,並且在聲明的同時進行賦值。
function fun(){
var a=0, b=1, c=2; //等同於var a=0; var b=1; var c=2;
}
fun();
alert(c); //腳本報錯,因為c是局部變量
3、全局對象window
var mystring = "平底斜";
console.log(mystring);
console.log(window.mystring);
console.log(window["mystring"]);
console.log(this.mystring);
console.log(this["mystring"]);//此處this就是window,針對this以後會專題講解
全局變量都可以看做window的屬性,使用方法就如以上代碼:可以用"."也可以用"[]"甚至可以省略window
局部變量只有一種情況:在函數內部聲明的變量擁有局部作用域
function fun(){
var mystring="平底斜"; //局部變量
console.log(mystring);
}
fun();
console.log(mystring); //腳本報錯
冷知識:
全局變量中,使用var聲明與不使用var是有區別的,var聲明的變量無法刪除,未聲明的變量可以刪除。
var mystring="平底斜";
newstring = "博客園";
delete mystring;
delete newstring;
console.log(mystring); //"平底斜"
console.log(newstring); //腳本報錯
作用域鏈由內向外查找變量,在內部找到變量便停止查找,否則往上一層作用域查找,直到最外層都沒有找到變量則返回undefined
var myscope = "平底斜";
function fun(){
var myscope = "博客園";
console.log(myscope); //"博客園"
}
fun();
上面這段代碼,就是因為作用域鏈有內向外,先在函數內部查找myscope,找到了就直接返回該變量值,並停止查找。
易錯點:
var myscope = "平底斜";
function fun(){
console.log(myscope); //腳本報錯
var myscope = "博客園";
console.log(myscope); //"博客園"
}
fun();
聲明變量會在當前作用域中置頂,又叫變量提升或者聲明置頂。以上代碼等同於:
var myscope = "平底斜";
function fun(){
var myscope;
console.log(myscope); //腳本報錯
myscope = "博客園";
console.log(myscope); //"博客園"
}
fun();
需要注意的是變量提升是在函數定義時發生,並不是在函數調用時:
var myscope = "平底斜";
function fun1(){
console.log(myscope);
}
function fun2(){
var myscope = "博客園";
fun1();
}
fun2(); //"平底斜"
如上,fun2()調用fun1()時,是先在fun1()中搜索myscope,找不到時再到父級作用域中查找。作用域的嵌套關系是在定義時產生,而不是在調用的時候。