作用域
- JavaScript中作用域的概念和C語言一樣, 也分為全局作用域和局部作用域
- 全局作用域
- 在任何地方都可以訪問到的就是全局作用域
- 在script標(biāo)簽中或一個(gè)獨(dú)立js文件中定義的就是全局作用域
<script>
var num = 10; // 該變量是全局作用域
function test() {
// 在函數(shù)中訪問全局作用域num變量
console.log("test中"+num);
}
test();
// 在外面訪問全局作用域num變量
console.log("外部"+num);
</script>
function test() { // 該函數(shù)是全局作用域
console.log("test函數(shù)");
}
// 在外面訪問全局作用域test函數(shù)
test();
function demo() {
// 在函數(shù)中訪問全局作用域test函數(shù)
test();
}
demo();
- 局部作用域
- 只在固定的代碼片段內(nèi)可訪問到的變量盆均,例如函數(shù)內(nèi)部。對應(yīng)局部作用域(函數(shù)作用域)
- 寫在函數(shù)內(nèi)部的都是局部作用域, 只能在當(dāng)前函數(shù)內(nèi)訪問
<script>
function test() {
var num = 123; // 該變量是局部作用域
// 可以在同一個(gè)局部作用域中訪問
console.log("test中"+ num);
}
// 不能在局部范圍以外訪問
console.log("外部"+num);
</script>
<script>
function test() {
function demo() { // 該函數(shù)是局部作用域
console.log("demo函數(shù)");
}
// 可以在同一個(gè)局部作用域中訪問
demo();
}
// 不能在局部范圍以外訪問
demo();
</script>
- 注意點(diǎn):
- 如果在函數(shù)中定義變量時(shí),如果不添加var關(guān)鍵字, 這個(gè)變量是一個(gè)全局變量
<script>
function test() {
// 企業(yè)開發(fā)千萬不要這么寫
num = 123;
console.log(num);
}
test();
console.log(num);
</script>
- 任何一對花括號({和})中的語句集都屬于一個(gè)塊,在這之中定義的所有變量在代碼塊外都是不可見的番宁,我們稱之為塊級作用域。
- 在es5之前沒有塊級作用域的的概念,只有函數(shù)作用域,現(xiàn)階段可以認(rèn)為JavaScript沒有塊級作用域
作用域鏈
- JavaScript代碼中至少有一個(gè)作用域, 即全局作用域。
- 凡是代碼中有函數(shù)嘱朽,那么這個(gè)函數(shù)就構(gòu)成另一個(gè)作用域。
- 如果函數(shù)中還有函數(shù)怔接,那么在這個(gè)作用域中就又可以誕生一個(gè)作用域搪泳。
- 將這樣的所有的作用域列出來,可以形成的結(jié)構(gòu)就稱之為作用域鏈蜕提。
<script>
var num = 123; // 0級作用域鏈
function test() { // 0級作用域鏈
var num = 666; // 1級作用域鏈
console.log(num);
function demo() { // 2級作用域鏈
var num = 777;
console.log(num);
}
demo();
}
test();
console.log(num);
</script>
再直白一點(diǎn): 訪問時(shí)就是C語言中的就近原則
預(yù)解析
- JavaScript代碼的執(zhí)行是由瀏覽器中的JavaScript解析器來執(zhí)行的森书。
- JavaScript解析器執(zhí)行JavaScript代碼的時(shí)候,分為兩個(gè)過程:
- 預(yù)解析過程
- 代碼執(zhí)行過程
- 預(yù)解析過程:
- 把變量的聲明提升到當(dāng)前作用域的最前面谎势,只會(huì)提升聲明,不會(huì)提升賦值杨名。
- 把函數(shù)的聲明提升到當(dāng)前作用域的最前面脏榆,只會(huì)提升聲明,不會(huì)提升調(diào)用台谍。
- 先提升var须喂,在提升function。
- 案例1
<script>
console.log(num); // undefined
var num = 123;
</script>
<script>
// 把變量的聲明提升到當(dāng)前作用域的最前面
var num;
console.log(num);
num = 123;
</script>
- 案例2:
<script>
test();
function test() {
console.log("hello world");
}
</script>
<script>
test();
alert(test);
function test() {
console.log("hello world");
}
</script>
<script>
// 把函數(shù)的聲明提升到當(dāng)前作用域的最前面
function test() {
console.log("hello world");
}
test();
alert(test);
</script>
- 預(yù)解析練習(xí)
var num = 123;
fun();
function fun() {
console.log(num);
var num = 666;
}
/*
var num;
function fun() {
var num;
console.log(num);
num = 666;
}
num = 123;
fun();
*/
var a = 666;
test();
function test() {
var b = 777;
console.log(a);
console.log(b);
var a = 888;
}
/*
var a;
function test() {
var b;
var a;
b = 777;
console.log(a);
console.log(b);
a = 888;
}
a = 666;
test();
*/
- 注意點(diǎn):
- 變量和函數(shù)同名時(shí), 函數(shù)的優(yōu)先級高
<script>
console.log(num);
function num() {
console.log("hello world");
}
var num = 666;
console.log(num);
/*
function num() {
console.log("hello world");
}
var num;
console.log(num);
num = 666;
console.log(num);
*/
</script>
不同方式定義函數(shù)區(qū)別
- 預(yù)解析時(shí)提升的方式不同
<script>
// 1.函數(shù)聲明
test();
function test() {
console.log("指趣學(xué)院");
}
// 2.函數(shù)表達(dá)式
demo(); // 報(bào)錯(cuò)
var demo = function () {
console.log("www.it666.com");
}
/*
function test() {
console.log("指趣學(xué)院");
}
var demo;
test();
demo();
demo = function () {
console.log("www.it666.com");
}
*/
</script>
- 新舊版本瀏覽器預(yù)解析處理方式不同
<script>
/*
在新版本瀏覽器中, 代碼塊中的函數(shù)不會(huì)被提升
在舊版本瀏覽器中, 代碼塊中的函數(shù)會(huì)被提升
新版本輸出"指趣學(xué)院"
老版本輸出"www.it666.com"
*/
if(true){
function test() {
console.log("指趣學(xué)院");
}
}else{
function test() {
console.log("www.it666.com");
}
}
test();
</script>
<script>
var test;
if(true){
test = function () {
console.log("指趣學(xué)院");
}
}else{
test = function() {
console.log("www.it666.com");
}
}
test();
</script>