《JavaScript高級程序設計》總結(六)—— 做用域和變量提高

函數變量的做用域

就是變量聲明的區域,就是變量和函數的可訪問範圍javascript

全局變量

在全局做用域中聲明的變量叫作全局變量,全局做用域的變量能夠在js中任何地方調用 ,變量沒有在函數內聲明或者聲明的時候沒有帶var就是全局變量,擁有全局做用域。特殊:var a = b = c = 0; b與c是全局變量。java

局部變量

如,在函數內部聲明的變量只能在函數內部訪問es6

塊級做用域

在javascript中,函數裏面定義的變量,能夠在函數裏面被訪問,但在函數外沒法訪問。而由花括號封閉的代碼塊都有本身的做用域,於是支持根據條件來定義變量,變量在執行完畢後會被銷燬,注意在es6以前的版本,並無塊級做用域,只有函數做用域和全局做用域,for循環的循環體中是函數做用域,for循環內部定義的變量在整個所在的函數內部是能夠訪問的。bash

舉個栗子函數

for(var i =0;i<10;i++){
            //console.log(i)
        }  
        console.log(i) //這裏i打印爲10,i的做用域是全局做用域
複製代碼

咱們來舉個複雜一點的函數來分析下其中變量的做用域

var t = 9; 
        function f1() { 
            var t2 = 10; 
            console.log(t);
            console.log(t3)
            function f2() { 
                var t3 = 200; 
                console.log(t2); 
                return t2 * t2;
            }
            return  f2()
            
        }
        f1();
複製代碼
  • 1.變量t的做用域爲全局做用域,任何地方都能訪問到它
  • 2.函數f1的做用域爲全局做用域,任何地方都能訪問到它
  • 3.在函數f1的內部,變量t2的做用域爲函數做用域f1,在函數f1中的任何地方均可以訪問到它
  • 4.函數f2的做用域爲函數做用域f1,在函數f1中的任何地方均可以訪問到它
  • 5.在函數f2中,變量t3的做用域爲函數做用域f2,在函數f2中的任何地方均可以訪問到它

這樣就造成了一個做用域鏈f2.Scope ===> f1.Scope ===> global.Scopeui

函數在執行的時候會沿着最末端的做用域依次向上查找變量,所以,子域能夠訪問父域的變量,而父域不能夠訪問子域的es5

上述代碼的執行結果爲spa

var t = 9; 
        function f1() { 
            var t2 = 10; 
            console.log(t);//9
            console.log(t3)//父級不能夠訪問子級的變量。報錯 not defined
            function f2() { 
                var t3 = 200; 
                console.log(t2); //10
                return t2 * t2; 
            }
            return  f2()
            
        }
        f1();
複製代碼

變量提高

若是一個聲明的變量在函數體內,那麼它的做用域就是函數內部。若是是在全局環境下聲明的,那麼它的做用域就是全局的。經過var聲明的變量是沒法用delete刪除的。code

函數內部的聲明的變量會被提高到函數的頭部。函數在解析執行的時候,先進行變量聲明處理,而後再運行函數內部的代碼。ip

變量和賦值語句一塊兒書寫,在js引擎解析時,會將其拆成聲明和賦值2部分,聲明置頂,賦值保留在原來位置

function a(){
    var b = 1
}
複製代碼

上述代碼就至關於

function a(){
    var b 
    b = 1
}
複製代碼

變量重複聲明不會出錯,後面的會覆蓋前面的。

var a = 1
var a = 2 
console.log(a)//被覆蓋,a的值爲2
複製代碼

當函數名和變量名相同時, 函數 > 變量,也就是先函數提高,後變量提高

var a = 1
function a(){
    
}
console.log(a)//a打印1
複製代碼

既然是先函數提高後變量提高那爲何會打印變量的值呢,由於,重複聲明是會被後面的覆蓋的

上述代碼至關於

var a = function(){
    
}

var a = 1
console.log(a)//a打印1
複製代碼

咱們來看幾個題目在鞏固一下做用域和變量提高

1.

if (!("a" in window)) { 
var a = 1; 
} 
console.log(a);
複製代碼

答案

if (!("a" in window)) { 
var a = 1; 
} 
console.log(a);//undefined
複製代碼

分析

1."a" in window是判斷在全局做用域中存不存在a,若存在則爲true,不存在爲fasle
2.在es5中函數是沒有塊級做用域的,所以在if中定義的變量的做用域爲包括此if語句的做用域,即變量a的做用域爲全局做用域
3.在js執行過程當中會先進行變量提高,所以在全局中先聲明一個變量a
4.if()的判斷爲false,所以不會a不會賦值
5打印a爲undefined


var a
if (!("a" in window)) { // true
 a = 1; 
} 
console.log(a);//undefined
複製代碼

2.

var a = 18;
function d() {
  console.log(a);
  var a = { age: 19};
  console.log(a);
}
d();  //  輸出?
console.log(a);

複製代碼

答案

var a = 18;
function d() {
  console.log(a);//undefiend
  var a = { age: 19};
  console.log(a); //{ age: 19};
}
d();  //  輸出?
console.log(a);//18
複製代碼

分析

在訪問變量時會先在訪問的做用域進行查找
1.函數d在執行的時候,遇到var a = {age:19}時進行了變量提高,只聲明沒有賦值,所以第一個打印語句打印undefined
2.全局中的a在全局中查找,打印18


//至關於
var a 
a = 18;
function d() {
  var a 
  console.log(a);//undefiend
  a = { age: 19};
  console.log(a); //{ age: 19};
}
d();  //  輸出?
console.log(a);//18


複製代碼

小練習

練習1

console.log(a);
var a = 20;
console.log(a);
function a() {
}

複製代碼

練習2

f();
console.log(a);
console.log(b);
console.log(c);
function f() {
    var a = b = c = 9;
    console.log(a);
    console.log(b);
    console.log(c);
}

複製代碼

練習3

f();
function f() {
for(var k = 0; k <10; k++) {
	console.log(k);
}
console.log(k);
}

複製代碼

答案

練習1

console.log(a); //打印函數a 
        var a = 20;
        console.log(a); //20
        function a() {
        }
複製代碼

練習2

f();
console.log(a);//Uncaught ReferenceError: a is not defined
console.log(b);//若是代碼能夠執行到這裏(忽略上述行的報錯),打印9
console.log(c);//若是代碼能夠執行到這裏(忽略上述行的報錯),打印9
function f() {
    var a = b = c = 9;
    console.log(a);//9
    console.log(b);//9
    console.log(c);//9
}
複製代碼
相關文章
相關標籤/搜索