(一)做用域是什麼瀏覽器
瞭解做用域以前先看一下變量和函數,變量和函數都有必定的訪問權限,就是必須知足條件或者在某個範圍以內才能訪問,這個範圍就是做用域。bash
它具體表現形式就是一段特定的代碼,在該代碼段中的變量和函數是封閉的、獨立的,這樣變量纔不會泄露、污染。函數
var cat = '有魚';
function Person(){
var name = '張三';
console.log(name);//張三,在函數內部,跟變量name在同一個做用域內
}
console.log(cat);//有魚
console.log(name);//沒有結果顯示,由於name在函數內部是獨立的,訪問不了
複製代碼
(二)做用域分類ui
做用域一共有三種,分別爲全局做用域、函數做用域、塊做用域,其中塊做用域是ES6新增的,同時函數做用域和塊做用域統稱爲局部做用域。spa
全局做用域code
在代碼的最外層的變量和函數稱爲全局做用域,有如下特色:對象
①在代碼的任何地方均可以訪問獲得作用域
②變量聲明時若是省略var關鍵字,則爲全局變量,擁有全局做用域string
③window對象的屬性和方法,擁有全局做用域it
④瀏覽器打開時開啓,瀏覽器關閉或者頁面關閉時銷燬
var cat = '有魚';
function Person(){
var name = '張三';
per = '卡卡';// 省略var,視爲全局變量
console.log(cat);//有魚 cat爲全局變量,函數Person內部能夠訪問
}
console.log(cat);//有魚 cat爲全局變量,最外層代碼能夠訪問
console.log(per);//卡卡 per爲全局變量,最外層代碼能夠訪問
複製代碼
全局做用域也有弊端,如:變量命名時容易重複,形成變量污染;
函數做用域
在函數內部的變量權限稱爲函數做用域,有如下特色:
①每一個函數都有本身的做用域,並且調用一次就會生成新的做用域
②只能在函數內部才能訪問,外部是沒有權限訪問的
③進入函數內部時開啓,函數執行完畢後銷燬
var cat = '有魚';
function Person(){
var name = '張三';
console.log(name);//張三 name爲函數做用域,函數Person內部能夠訪問
}
console.log(name);//有魚 name爲函數做用域,最外層代碼沒有權限訪問
複製代碼
塊做用域(ES6新增)
凡是由{}符號包裹起來的都是塊做用域,ES6新增的知識點,有如下特色:
①只能在{}內部起做用
②變量聲明時使用let或const關鍵字
③變量名不能重複,不然會報錯
④變量不能夠在聲明以前使用
使用var進行展現:
if(true){
var cat = '有魚';
console.log(cat);//有魚
}
console.log(cat);//有魚
複製代碼
使用let進行展現:
if(true){
let cat = '有魚';
console.log(cat);// 有魚
// let cat = '年年';// Uncaught SyntaxError: Identifier 'cat' has already been declared
}
console.log(cat);// 訪問不了cat變量 報:Uncaught ReferenceError: cat is not defined
複製代碼
注意:塊做用域通常用在for等循環語句中,能夠避免變量外泄
(三)變量提高與函數提高
變量提高
①var關鍵字存在變量提高,let、const不存在;
②變量提高的意思是在程序執行前,先去整個代碼中查看是否含有變量聲明,便是否有var關鍵字,若是有則先執行聲明,而後再去執行其餘部分。
這裏我我總結了4句話:
①js程序執行的順序,先看var聲明,聲明部分在第一行,其餘(賦值)按照正常順序執行
②若是局部變量裏面有var聲明,就是局部變量,不用管外面的全局變量
③若是局部變量裏面沒有var聲明,就去找外面的全局變量
④在局部變量裏面,如何使用全局變量,使用window對象調用
var a = "Hello";
function person(){
var a;
console.log(a);//undifined
a = "World";
console.log(a);//World
}
person();
console.log(a);//Hello
// 先看整個腳本文件的聲明部分,全局做用域有個變量a,局部做用域也有個變量a,並且都有var聲明,說明他們是徹底兩個不一樣的變量,此時函數內部不用管外面的全局變量,此時變量a只是聲明而沒有賦值,因此輸出爲 undifined;
// 接着仍是局部做用域裏面,給a進行了賦值,此時輸出時爲world,且還是局部變量;
// 函數外部的輸出時,由於局部做用域已經結束,則又恢復到全局變量中,因此此時輸出的是全局變量啊,值爲hello。
複製代碼
var a = "Hello";
function person(){
console.log(a);//Hello
a = "World";
console.log(a);//World
}
person();
console.log(a);//World
// 先看整個腳本文件的聲明部分,全局做用域有個變量a,局部做用域裏面沒有var聲明,則此時a是一個所有變量,因此輸出時a的值就是所有變量hello;
// 局部做用域裏面對全局變量a進行了從新賦值,因此此時輸出時爲world
// 函數外部的輸出時,由於跳出局部做用域,又恢復到全局變量中,以前由於已經從新賦值爲world,此時輸出時爲world
複製代碼
var a = "Hello";
function person(){
console.log(a);//undifined
var a = "World";
console.log(a);//World
}
person();
console.log(a);// Hello
// 先看整個腳本文件的聲明部分,全局做用域有個變量a,局部做用域也有個變量a,且有var聲明,說明他們是徹底兩個不一樣的變量,此時函數內部不用管外面的全局變量,進行變量提高,記住只是聲明提高,賦值不進行提高,因此輸出爲 undifined;
// 仍是局部做用域裏面,給a進行了賦值,此時輸出時爲World,且還是局部變量
// 函數外部的輸出時,由於局部做用域已經結束,則又恢復到全局變量中,因此此時輸出時爲Hello
複製代碼
var a = "Hello";
function person(){
console.log(window.a); //Hello 由於是window對象的屬性,此時a是全局變量
var a = "World"; //局部變量a在這行定義
console.log(a); //World
}
person();
console.log(a);//Hello 全局變量a
// 在局部做用域使用全局變量使用window.全局變量名字
複製代碼
函數提高
①函數有兩種形式:函數表達式 var per = function(){} 、函數聲明 function per(){},只有函數聲明有函數提高特性
②提高的意思是容許先調用,後聲明
per();//能夠先調用
function per(){
console('我是函數聲明形式,容許提高');
}
複製代碼
(一)什麼是做用域鏈
每一層做用域其實就是一個執行環境(做用域和執行環境是有區別的,這裏爲了容易理解,姑且這樣),在該環境內執行程序時,會建立一個變量對象,對象包含該有屬於本身的變量和函數;
在當前執行環境下找不變量時,就會向上一層做用域裏面尋找,具體過程仍是先找到上一層的變量對象,再去裏面找對應的變量,若是仍是找不到,繼續向上……
直到最外層的做用域,也就是全局做用域,這樣就會造成一個鏈條,稱爲做用域鏈。
(二)做用域特色
①做用域鏈最外層是全局做用域,最內層是當前做用域
②內部環境能夠經過做用域鏈訪問全部外部環境,但外部環境不能訪問內部環境的任何變量和函數
③因爲變量的查找是沿着做用域鏈來實現的,因此也稱做用域鏈爲變量查找的機制
var cat = '有魚';
function Person() {
var name = '張三';
function Student() {
var age = 18;
console.log(name);//張三
console.log(cat);//有魚
}
Student();
console.log(age);//Uncaught ReferenceError: age is not defined
}
Person();
//Student函數內部屬於最內層做用域,找不到name,向上一層做用域Person函數內部找,找到了輸出‘張三’;
//在Student內部輸出cat時找不到,向上一層做用域Person函數找,還找不到繼續向上一層找,即全局做用域,找到了輸出‘有魚’;
//在Person函數內部輸出age時找不到,向上一層做用域找,即全局做用域,仍是找不到輸出‘age is not defined’;
複製代碼