深入理解JavaScript的作用域和作用域鏈

一、作用域
(一)作用域是什么
了解作用域之前先看一下變量和函數(shù),變量和函數(shù)都有一定的訪問權限京革,就是必須滿足條件或者在某個范圍之內(nèi)才能訪問泥栖,這個范圍就是作用域。它具體表現(xiàn)形式就是一段特定的代碼弧满,在該代碼段中的變量和函數(shù)是封閉的婆跑、獨立的,這樣變量才不會泄露庭呜、污染滑进。
var cat = '有魚';
function Person(){
var name = '張三';
console.log(name);//張三,在函數(shù)內(nèi)部募谎,跟變量name在同一個作用域內(nèi)
}
console.log(cat);//有魚
console.log(name);//沒有結果顯示扶关,因為name在函數(shù)內(nèi)部是獨立的,訪問不了
(二)作用域分類
作用域一共有三種数冬,分別為全局作用域节槐、函數(shù)作用域、塊作用域,其中塊作用域是ES6新增的铜异,同時函數(shù)作用域和塊作用域統(tǒng)稱為局部作用域地来。
全局作用域
在代碼的最外層的變量和函數(shù)稱為全局作用域,有以下特點:
①在代碼的任何地方都可以訪問得到
②變量聲明時如果省略var關鍵字熙掺,則為全局變量未斑,擁有全局作用域
③window對象的屬性和方法,擁有全局作用域
④瀏覽器打開時開啟币绩,瀏覽器關閉或者頁面關閉時銷毀
var cat = '有魚';
function Person(){
var name = '張三';
per = '卡卡';// 省略var蜡秽,視為全局變量
console.log(cat);//有魚 cat為全局變量,函數(shù)Person內(nèi)部可以訪問
}
console.log(cat);//有魚 cat為全局變量缆镣,最外層代碼可以訪問
console.log(per);//卡卡 per為全局變量芽突,最外層代碼可以訪問
全局作用域也有弊端,如:變量命名時容易重復董瞻,造成變量污染寞蚌;
函數(shù)作用域
在函數(shù)內(nèi)部的變量權限稱為函數(shù)作用域,有以下特點:
①每個函數(shù)都有自己的作用域钠糊,而且調(diào)用一次就會生成新的作用域
②只能在函數(shù)內(nèi)部才能訪問挟秤,外部是沒有權限訪問的
③進入函數(shù)內(nèi)部時開啟,函數(shù)執(zhí)行完畢后銷毀
var cat = '有魚';
function Person(){
var name = '張三';
console.log(name);//張三 name為函數(shù)作用域抄伍,函數(shù)Person內(nèi)部可以訪問
}
console.log(name);//有魚 name為函數(shù)作用域艘刚,最外層代碼沒有權限訪問

塊作用域(ES6新增)
凡是由{}符號包裹起來的都是塊作用域,ES6新增的知識點截珍,有以下特點:
①只能在{}內(nèi)部起作用
②變量聲明時使用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等循環(huán)語句中,可以避免變量外泄
(三)變量提升與函數(shù)提升
變量提升
①var關鍵字存在變量提升岗喉,let秋度、const不存在;
②變量提升的意思是在程序執(zhí)行前钱床,先去整個代碼中查看是否含有變量聲明荚斯,即是否有var關鍵字,如果有則先執(zhí)行聲明诞丽,然后再去執(zhí)行其他部分鲸拥。
這里我我總結了4句話:
①js程序執(zhí)行的順序,先看var聲明僧免,聲明部分在第一行刑赶,其他(賦值)按照正常順序執(zhí)行
②如果局部變量里面有var聲明,就是局部變量懂衩,不用管外面的全局變量
③如果局部變量里面沒有var聲明撞叨,就去找外面的全局變量
④在局部變量里面金踪,如何使用全局變量,使用window對象調(diào)用
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聲明枷餐,說明他們是完全兩個不同的變量靶瘸,此時函數(shù)內(nèi)部不用管外面的全局變量,此時變量a只是聲明而沒有賦值毛肋,所以輸出為 undifined怨咪;
// 接著還是局部作用域里面,給a進行了賦值润匙,此時輸出時為world诗眨,且仍是局部變量;
// 函數(shù)外部的輸出時孕讳,因為局部作用域已經(jīng)結束匠楚,則又恢復到全局變量中,所以此時輸出的是全局變量啊厂财,值為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
// 函數(shù)外部的輸出時梅鹦,因為跳出局部作用域裆甩,又恢復到全局變量中,之前因為已經(jīng)重新賦值為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聲明茉帅,說明他們是完全兩個不同的變量,此時函數(shù)內(nèi)部不用管外面的全局變量锭弊,進行變量提升堪澎,記住只是聲明提升,賦值不進行提升味滞,所以輸出為 undifined樱蛤;
// 還是局部作用域里面钮呀,給a進行了賦值,此時輸出時為World昨凡,且仍是局部變量
// 函數(shù)外部的輸出時爽醋,因為局部作用域已經(jīng)結束,則又恢復到全局變量中便脊,所以此時輸出時為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.全局變量名字

函數(shù)提升
函數(shù)有兩種形式:函數(shù)表達式 var per = function(){} 、函數(shù)聲明 function per(){}哪痰,只有函數(shù)聲明有函數(shù)提升特性
提升的意思是允許先調(diào)用遂赠,后聲明
per();//可以先調(diào)用
function per(){
console('我是函數(shù)聲明形式,允許提升');
}

二妒御、作用域鏈
(一)什么是作用域鏈
每一層作用域其實就是一個執(zhí)行環(huán)境(作用域和執(zhí)行環(huán)境是有區(qū)別的解愤,這里為了容易理解,姑且這樣)乎莉,在該環(huán)境內(nèi)執(zhí)行程序時送讲,會創(chuàng)建一個變量對象,對象包含該有屬于自己的變量和函數(shù)惋啃;
在當前執(zhí)行環(huán)境下找不變量時哼鬓,就會向上一層作用域里面尋找,具體過程還是先找到上一層的變量對象边灭,再去里面找對應的變量异希,如果還是找不到,繼續(xù)向上……
直到最外層的作用域绒瘦,也就是全局作用域称簿,這樣就會形成一個鏈條,稱為作用域鏈惰帽。
(二)作用域特點
作用域鏈最外層是全局作用域憨降,最內(nèi)層是當前作用域
內(nèi)部環(huán)境可以通過作用域鏈訪問所有外部環(huán)境,但外部環(huán)境不能訪問內(nèi)部環(huán)境的任何變量和函數(shù)
由于變量的查找是沿著作用域鏈來實現(xiàn)的该酗,所以也稱作用域鏈為變量查找的機制
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函數(shù)內(nèi)部屬于最內(nèi)層作用域授药,找不到name,向上一層作用域Person函數(shù)內(nèi)部找呜魄,找到了輸出‘張三’悔叽;
②在Student內(nèi)部輸出cat時找不到,向上一層作用域Person函數(shù)找爵嗅,還找不到繼續(xù)向上一層找娇澎,即全局作用域,找到了輸出‘有魚’操骡;
③在Person函數(shù)內(nèi)部輸出age時找不到九火,向上一層作用域找赚窃,即全局作用域,還是找不到輸出‘a(chǎn)ge is not defined’岔激;

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勒极,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子虑鼎,更是在濱河造成了極大的恐慌辱匿,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炫彩,死亡現(xiàn)場離奇詭異匾七,居然都是意外死亡,警方通過查閱死者的電腦和手機江兢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門昨忆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杉允,你說我怎么就攤上這事邑贴。” “怎么了叔磷?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵拢驾,是天一觀的道長。 經(jīng)常有香客問我改基,道長繁疤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任秕狰,我火速辦了婚禮稠腊,結果婚禮上,老公的妹妹穿的比我還像新娘鸣哀。我一直安慰自己麻养,他們只是感情好,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布诺舔。 她就那樣靜靜地躺著,像睡著了一般备畦。 火紅的嫁衣襯著肌膚如雪低飒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天懂盐,我揣著相機與錄音褥赊,去河邊找鬼。 笑死莉恼,一個胖子當著我的面吹牛拌喉,可吹牛的內(nèi)容都是我干的速那。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼尿背,長吁一口氣:“原來是場噩夢啊……” “哼端仰!你這毒婦竟也來了?” 一聲冷哼從身側響起田藐,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荔烧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后汽久,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹤竭,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年景醇,在試婚紗的時候發(fā)現(xiàn)自己被綠了臀稚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡三痰,死狀恐怖吧寺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酒觅,我是刑警寧澤撮执,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站舷丹,受9級特大地震影響抒钱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颜凯,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一谋币、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧症概,春花似錦蕾额、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至募壕,卻和暖如春调炬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舱馅。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工缰泡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人代嗤。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓棘钞,卻偏偏與公主長得像缠借,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宜猜,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容