什么是作用域
作用域決定了代碼區塊中變數和其他資源的可見性,**作用域就是一個獨立的獨立的地盤,讓變數不外泄.暴露出去,作用域最大的用處就是隔離變數,不同作用域下變數名不會沖突
作用域可以分為
1.全域作用域,
2.私有作用域
3.es6塊級作用域
全域作用域
當打開頁面的時候,會提供一個供js代碼執行的環境,全域作用域,會默認提供一個最大的window物件,
【全域變數】:在全域作用域中宣告的變數就是全域變數,其中下面的a 和fn 就是全域變數
【全域變數和window關系】 在全域作用域中宣告的變數:var、function(除去es6的),相當于給window上添加了屬性,屬性名就是變數名,屬性值就是變數值
呼叫window 下的方法時,可以省去window不寫:
window.alert("1");
alert("1");
window.Number("1");
Number("1");
var a=3; // a是全域變數
function fn(){ // fn 是全域變數
var num=3;
function f1(){
}
}
console.log(window.a);
console.log(window.fn);
所有未定義直接賦值的變數自動宣告為擁有全域變數
所有window物件的屬性擁有全域作用域
所有window物件擁有全域作用域
全域作用域的弊端:如果我們寫了很多行代碼,變數定義沒有用函式包括,那么他們就全部在全域作用域中,這樣會污染全域命名空間容易引起命名沖突
函式作用域(私有作用域)
【私有變數】:
- 形參
- 在私有作用域中宣告的變數就是私有變數,
在私有作用域外面,去訪問私有變數的話,是訪問不到的,但是在私有作用域里面可以訪問到外面的變數,
var a = 66;
function fn() {
var x = 1;
var y = 3;
console.log(a);//66
return x + y;
}
console.log(x);// x is not defined
fn();
塊陳述句(大括號{}中間的陳述句)如Switch和if條件陳述句或for和while回圈陳述句,不像函式它們不會創建新的作用域,在塊陳述句級作用域中定義的變數將保留在他們已經存在的作用域中
es6塊級作用域
先來看一下es6中的let
let不存在變數提升
console.log(a);//Uncaught ReferenceError: a is not defined
let a=2;
阻斷了和window的關系
let a=2;
console.log(window.a);// undefined
不能重復宣告
es6中沒有變數提升,但是有一個自我檢測的一個機制,在代碼自上而下執行前,會先進行檢測,看是否有重復宣告的變數,如果有的話,就先報錯,
let a=2;
console.log(a);
var a=3; // 不能進行重復的宣告:Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(3);
暫時性死區
ES6明確規定,如果區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域,凡是在宣告之前就使用這些變數,就會報錯,在代碼塊內,使用let命令宣告變數之前,該變數都是不可用的,這在語法上,稱為“暫時性死區”(temporal dead zone,簡稱 TDZ),
我們來看塊級作用域
塊級作用域可以通過新增命令let和const宣告,所宣告的變數在指定塊的作用域外無法訪問,塊級作用域在如下情況被創建
1.在一個函式內部
2.在一個代碼塊(由一對花括號包裹)內部
我們來看回圈中的塊級作用域 更好的了解一下塊級作用域
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6]();//10
上面代碼中,變數i是var宣告的,在全域范圍內有效,全域中只有有一個變數i每次回圈i的值都會發生變化,而回圈內的i指向的是全域的i,也就是說所有陣列a的成員里面的i指向的都是同一個i導致運行時輸出的結果是最后一輪i的值 也就是10
再來看用let宣告的 宣告的變數僅在塊級作用域內部有效 最后輸出的結果是6
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6]();// 6
變數i是let宣告的,當前的i只在本輪回圈有效,所以每次回圈你的i其實都是一個新的變數所以最后輸出的結果是6
思考:如果每一輪回圈的變數i都是重復宣告的那它怎么知道上一輪回圈的值,從而計算出本輪回圈的值?
這是因為js引擎內部會記住上一輪回圈的值 ,初始化本輪的變數i時 就在上一輪回圈的基礎上進行計算
什么是作用域鏈
在私有作用域中,如果沒有定義這個私有變數,就會向上一級作用域進行查找,如果都沒有,繼續進行查找,直到查找到window為止,如果是賦值,宣告的時候用了var、function 就是給GO添加(也是給window)添加,不帶任何關鍵字的,相當于省了window,也是給Go添加,如果宣告的時候用了let、const 直接給VO添加,
上級作用域:
當前函式執行,形成一個私有作用域A,這個A的上級作用域是誰,跟它在哪執行無關,跟它在哪定義(創建)有關系,在哪創建,它的上級作用域就是誰
簡而言之:上級作用域和函式在哪執行無關,和函式在哪定義有關
練習題
console.log(a,b);// undefined undefined
var a=12,
b=12;
function fn(){
console.log(a,b);// undefined 12
var a=b=13;
console.log(a,b);// 13 13
}
fn();
console.log(a,b);// 12 13
[決議]
代碼自上而下執行之前會把var 和function進行變數和提升 var只宣告不定義function宣告和定義一起完成 ,
代碼自上而下執行 此時console.log(a,b) 都是undefined,提升階段函式fn已經不在執行直接跳過
在呼叫fn fn執行 會形成私有作用域普通函式執行
普通函式執行
- 會形成全新的私有背景關系
- 初始化自己的作用域鏈{自己的背景關系,上級背景關系'}
- 初始化this
- 初始化arguments
- 形參賦值
- 變數提升
- 代碼執行
- 默認回傳undefined
此時函式內部的a提升到自己作用域的頂部還是只宣告不定義 console.log(a,b)a 是undefined b會根據作用域鏈找到全域 b為12
var a=b=13; 此時b不帶var不是私有變數會向上一級作用域進行查找 如果還沒有找到,一直繼續向上查找直到找到window這種機制叫做作用域鏈查找, console.log(a,b)此時a是私有13,b不是私有變數,并將全域的b修改為13
console.log(a,b) 列印的是全域的ab 現在是 a12 b13

-------------------------------------完結--------------------------------------------------
-------------------------接收大佬們的批改和指點,歡迎留言-------------------------------------
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/340771.html
標籤:其他
