一禁漓、js作用域

一跟衅、理解js作用域

1、作用域:作用域是一套規(guī)則播歼,用于確定在何處以及如何查找變量(標(biāo)字符)伶跷。
2、LHS查詢:查找的目的是對(duì)變量進(jìn)行賦值荚恶;
3撩穿、RHS查詢:查找的目的是獲取變量的值;
(賦值操作符會(huì)導(dǎo)致LHS查詢谒撼、=操作符獲調(diào)用函數(shù)是傳入?yún)?shù)的操作會(huì)都會(huì)導(dǎo)致關(guān)聯(lián)作用域的賦值操作)
eg食寡、

function foo(a){
    var b=a;
    return a+b;
}
var c=foo(2);
//LHS查詢(3處)c=...、a=2(調(diào)用函數(shù)傳參的隱式變量分配)廓潜、b=..
//RHS查詢(4處)foo(2..)抵皱、=a、a..辩蛋、...b

4呻畸、JavaScript引擎會(huì)先在代碼執(zhí)行前對(duì)其進(jìn)行編譯,如var a=2分為兩個(gè)步驟:
(1)悼院、首先伤为,var a在其作用域中聲明新的變量a、這會(huì)在最開始的階段,也就是代碼執(zhí)行前進(jìn)行(聲明提前)绞愚;
(2)叙甸、接下來,a=2會(huì)查詢(LHS查詢)變量a并對(duì)其進(jìn)行賦值位衩。

LHS和RHS查詢都會(huì)在先在當(dāng)前執(zhí)行作用域中開始裆蒸,如果在當(dāng)前作用域中沒有找到所需標(biāo)識(shí)符,就會(huì)向上一級(jí)繼續(xù)查找直到頂層全局作用域糖驴;
**不成功的RHS引用會(huì)拋出referenceError異常僚祷;不成功的LHS引用會(huì)導(dǎo)致自動(dòng)隱式的創(chuàng)建一個(gè)全局變量(非嚴(yán)格模式下) **

二、詞法作用域

  • 定義
    贮缕。定義在詞法階段的作用域辙谜,由你寫代碼是將變量和塊作用域?qū)懺谀睦锼鶝Q定
  • 查找
    。作用域始終從運(yùn)行時(shí)所處的最內(nèi)部作用域開始查找跷睦,逐級(jí)向外部進(jìn)行筷弦,直到遇見第一個(gè)匹配的標(biāo)識(shí)符為止;
  • 詞法欺騙
    抑诸。在詞法階段通過代碼欺騙和假裝成書寫烂琴,來實(shí)現(xiàn)修改詞法作用域;
    蜕乡。欺騙詞法作用域會(huì)導(dǎo)致性能下降,應(yīng)盡量避免使用奸绷;
    。js中會(huì)“欺騙”詞法作用域的兩種機(jī)制:
    (1)eval(..)
    *可接收一字符串參數(shù)层玲,并將其內(nèi)容視為在書寫時(shí)就存在于程序中的這個(gè)位置号醉;
    eg:
function foo(str,a) {
    eval(str);//欺騙
    console.log(a,b);
    // body...
}
var b=2;
foo("var b=3;",1);//1  3

*在嚴(yán)格模式的程序中,eval()在運(yùn)行時(shí)有其自己的詞法作用域辛块,即其中的聲明無法修改所在的作用域畔派;
eg:

function foo(str,a) {
    "use strict";
    eval(str);//欺騙
    console.log(a,b);
    // body...
}
function foo1(str) {
    "use strict";
    eval(str);//欺騙
    console.log(a);//ReferenceError: a is not defined
    // body...
}
foo1("var a=3;");

(2)with
。重復(fù)引用同一對(duì)象中多個(gè)屬性的快捷方式润绵;
线椰。with可以將一個(gè)沒有或有多個(gè)屬性的對(duì)象處理為為一個(gè)完全隔離的詞法作用域,因此這個(gè)對(duì)象的屬性也會(huì)被處理為定義在這個(gè)作用域中的詞法標(biāo)識(shí)符尘盼。
eg:

function foo2(obj){
   with(obj){
        a=2; //實(shí)際是一個(gè)LHS引用
    }
}
var o1={
    a:3
};
var o2={
    b:3
};
foo2(o1);
console.log(o1.a);//2憨愉;o1傳遞進(jìn)去,a=2賦值操作找到o1.a并將2賦值給它
foo2(o2);
console.log(o2.a);//undefined:o2傳遞進(jìn)去卿捎,o2沒用a屬性配紫,因此不會(huì)創(chuàng)建這個(gè)屬性
console.log(a)//2----a被泄露到全局作用域

。o2午阵、foo(..)躺孝、和全局的作用域中都沒有找到標(biāo)識(shí)符a,因此當(dāng)a=2執(zhí)行時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè)全局變量(非嚴(yán)格模式)
。盡管with塊可以將一個(gè)對(duì)象處理為詞法作用域括细,但這個(gè)塊內(nèi)部的正常var聲明不會(huì)被限制在這個(gè)塊中伪很,而是被添加到with所處的函數(shù)作用域中。
eg:

function foo3(obj){
    with(obj){
        var a=2; //實(shí)際是一個(gè)LHS引用
}
}
var o1={
    a:3
};
var o2={
    b:3
};
foo3(o1);
console.log(o1.a);//2奋单;o1傳遞進(jìn)去,a=2賦值操作找到o1.a并將2賦值給它
foo3(o2);
console.log(o2.a);//undefined:o2傳遞進(jìn)去猫十,o2沒用a屬性览濒,因此不會(huì)創(chuàng)建這個(gè)屬性
console.log(a)//ReferenceError: a is not defined

三、函數(shù)作用域

  • 含義:
    拖云。指的是屬于這個(gè)函數(shù)的全部變量都可以在整個(gè)函數(shù)的范圍內(nèi)使用及復(fù)用(事實(shí)上在 嵌套的作用域中也可以使用)
  • 函數(shù)聲明和函數(shù)表達(dá)式:
    贷笛。區(qū)分:看function關(guān)鍵字出現(xiàn)在聲明中的位置;如果是聲明中的第一詞宙项,那么就是一個(gè)函數(shù)聲明乏苦,否則就是一個(gè)函數(shù)表達(dá)式.
  • IIEF立即執(zhí)行函數(shù)表達(dá)式
    eg:
var a=2;
(function IIEF(global){
    var a=3;
    console.log(a);//3
    console.log(global.a);//2
})(window);
console.log(a);//2

1)函數(shù)被包含在()中,因此成了一個(gè)表達(dá)式尤筐;通過后面的()可以立即執(zhí)行這個(gè)函數(shù)汇荐;
2)通過后面的()可傳入?yún)?shù),例中傳入window對(duì)象并命名為global盆繁。
掀淘。IIEF還有一種變化用途是倒置代碼的運(yùn)行順序,將需要運(yùn)行的函數(shù)放在第二位油昂,在IIEH執(zhí)行之后當(dāng)做參數(shù)傳遞進(jìn)去
eg:

var a = 2;
(function IIFE( def ) {
    def(window);
})(function def( global ) {
    var a = 3;
    console.log( a );   // 3
    console.log( global.a);   //2
});

四革娄、塊作用域

  • 在JavaScript中只有函數(shù)作用域,沒有塊級(jí)作用域冕碟。
for(var i = 0; i < 10; i++) {}console.log( i ); // 10

拦惋。在for循環(huán)的頭部定義了變量i,通常只是想在for循環(huán)內(nèi)部的上下文使用i安寺,而忽略了i會(huì)被綁定到外部作用域(函數(shù)或全局)厕妖。

var foo = true;if (foo) { var bar = foo * 2; }console.log( bar ); // 2

。bar變量雖然在if聲明中的上下文使用我衬,但它們最終都屬于外部作用域叹放。

  • ** with**
    。with也是塊級(jí)作用域的一種形式挠羔,用with從對(duì)象中創(chuàng)建出的作用域僅在with聲明中有效井仰。
  • ** try/catch**
    。ES3規(guī)范的try/catch的catch分句會(huì)創(chuàng)建一個(gè)塊級(jí)作用域破加,其中聲明的變量只在catch內(nèi)部有效俱恶。
try {
 foo();
}
catch(err) {
 var a = 0; console.log( err ); //可以執(zhí)行
}
console.log( a ); // 0;
console.log( err ); // err not found
  • let
    。ES6的let可以將變量綁定到所在的任意作用域(通常是{...})。
var foo = true;
if (foo) {
 let bar = foo * 2;
 console.log( bar ); // 2
}
console.log( bar ); //referenceError
合是。**使用let進(jìn)行的聲明不會(huì)在塊級(jí)作用域中提升了罪。聲明的代碼被運(yùn)行前,聲明并不“存在”聪全。**
console.log( bar ); //ReferenceError
 let bar = 2;
  • ** const**
    泊藕。 ES6引入const同樣能創(chuàng)建塊級(jí)作用域,但其值是常量难礼。
var foo = true;
if (foo) { 
var a = 2;
 const b = 3; // 包含在if中的塊級(jí)作用域常量
 a = 3;
 b = 4; // 錯(cuò)誤
}
console.log( a ); // 3
console.log( b ); // ReferenceError

五娃圆、提升(聲明提前)

eg:

foo();
function foo(){
    a=2;
    console.log(a);//2
    var a;
}

。定義聲明如var a蛾茉;是在編譯階段進(jìn)行的讼呢;賦值聲明會(huì)留在原地等待執(zhí)行階段;
谦炬。簡(jiǎn)單講悦屏,即包含變量和函數(shù)在內(nèi)的所有聲明都會(huì)在任何代碼被執(zhí)行之前首先被處理.
。注意:函數(shù)聲明會(huì)被提升键思,當(dāng)是函數(shù)表達(dá)式不會(huì)被提升础爬。(下例中,var ber被提升稚机,但函數(shù)表達(dá)式..=function foo(){}并不會(huì)提升幕帆,故ber()拋出TypeError異常而不是ReferenceError)
eg:

ber();  //TypeError: ber is not a function
var ber=function foo(){
    a=2;
    console.log(a);
    var a;
}
  • 函數(shù)優(yōu)先
    。函數(shù)聲明和變量聲明都會(huì)被提升赖条,但是函數(shù)會(huì)首先被提升失乾,然后才是變量
    eg:
foo1();//a
var foo1;
function foo1(){
    console.log("a");
};
foo1=function(){
    console.log("b")
};
foo1()//b
。以上代碼被引擎理解為:
function foo1(){
    console.log("a");
}
foo1();//a
foo1=function(){
    console.log("b")
}
foo1()//b
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纬乍,一起剝皮案震驚了整個(gè)濱河市碱茁,隨后出現(xiàn)的幾起案子帽借,更是在濱河造成了極大的恐慌林螃,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件储笑,死亡現(xiàn)場(chǎng)離奇詭異茧泪,居然都是意外死亡蜓氨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門队伟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穴吹,“玉大人,你說我怎么就攤上這事嗜侮「哿睿” “怎么了啥容?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)顷霹。 經(jīng)常有香客問我咪惠,道長(zhǎng),這世上最難降的妖魔是什么淋淀? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任遥昧,我火速辦了婚禮,結(jié)果婚禮上朵纷,老公的妹妹穿的比我還像新娘渠鸽。我一直安慰自己,他們只是感情好柴罐,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著憨奸,像睡著了一般革屠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上排宰,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天似芝,我揣著相機(jī)與錄音,去河邊找鬼板甘。 笑死党瓮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盐类。 我是一名探鬼主播寞奸,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼在跳!你這毒婦竟也來了枪萄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤猫妙,失蹤者是張志新(化名)和其女友劉穎瓷翻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體割坠,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齐帚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彼哼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片对妄。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沪羔,靈堂內(nèi)的尸體忽然破棺而出饥伊,到底是詐尸還是另有隱情象浑,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布琅豆,位于F島的核電站愉豺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏茫因。R本人自食惡果不足惜蚪拦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冻押。 院中可真熱鬧驰贷,春花似錦、人聲如沸洛巢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稿茉。三九已至锹锰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漓库,已是汗流浹背恃慧。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渺蒿,地道東北人痢士。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像茂装,于是被迫代替她去往敵國(guó)和親怠蹂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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