亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

淺談JavaScript作用域

figofuture / 3506人閱讀

摘要:我們?cè)诿嬖嚂r(shí),總會(huì)碰到一些奇奇怪怪的關(guān)于作用域的面試題,其實(shí)弄清楚原理,萬(wàn)變不離其宗,大部分的面試題都可以得姐。

我們?cè)诿嬖嚂r(shí),總會(huì)碰到一些奇奇怪怪的關(guān)于 作用域 的面試題,其實(shí)弄清楚原理,萬(wàn)變不離其宗,大部分的面試題都可以得 ‘姐’。

所以,今天我們來(lái)談?wù)?JavaScript作用域(javascript scope) ,這是老生常談的話題,這里我們會(huì)從 作用域 開(kāi)始,會(huì)延伸到 預(yù)解析規(guī)則(預(yù)編譯) 、 表達(dá)式變量提升 、 函數(shù)提升匿名函數(shù)表達(dá)式具名函數(shù)表達(dá)式 等,徹底搞明白作用域這些事 ?

詳情,可查看我的博客 lishaoy.net

變量提升和函數(shù)提升

在開(kāi)始闡述之前,我們來(lái)看一段代碼,看看結(jié)果是什么?

alert(a);
function a(){ alter(2); }
alert(a);
var a = 1
alert(a);
var a = 3;
alert(a);
function a(){ alter(4); }
alert(a);
a();

這里先揭曉答案:

第一個(gè) alert(a) 彈出 function a(){ alter(4); } 函數(shù)體

第二個(gè) alter(a) 彈出 function a(){ alter(4); } 函數(shù)體

第三個(gè) alter(a) 彈出 1

第四個(gè) alter(a) 彈出 3

第五個(gè) alter(a) 彈出 3

最后一行報(bào)錯(cuò) a is not a function

下面來(lái)分析一下這段代碼:
其實(shí)在 javascript 開(kāi)始執(zhí)行代碼之前,有一個(gè) 預(yù)解析(預(yù)編譯) 的過(guò)程,這個(gè)過(guò)程會(huì)產(chǎn)生 變量提升函數(shù)提升 ,其實(shí)整個(gè)執(zhí)行過(guò)程可以分為兩部分,方便理解:

預(yù)解析

這個(gè)過(guò)程,會(huì)把 關(guān)鍵字 var 、 function 、 參數(shù) 提取出來(lái)

上面這段代碼 預(yù)解析 的過(guò)程是:

// 第1行,沒(méi)有關(guān)鍵字 , 不解析
// 第2行,遇到 function 關(guān)鍵字,解析到全局的頭部
a = function a(){ alter(2); }
// 第3行,沒(méi)有關(guān)鍵字 , 不解析
// 第4行,遇到關(guān)鍵字 var , 解析到全局的頭部
a = undefined
// 第5行,沒(méi)有關(guān)鍵字 , 不解析
// 第6行,遇到關(guān)鍵字 var , 解析到全局的頭部
a = undefined
// 第8行,遇到 function 關(guān)鍵字,解析到全局的頭部
a = function a(){ alter(4); }
// 第9行,沒(méi)有關(guān)鍵字 , 不解析
// 第10行,a() 函數(shù)調(diào)用

此時(shí)這里有4個(gè)同名變量 a ,依循規(guī)則是:function 優(yōu)先與 var, 同名的后面覆蓋前面的
因此,a = function a(){ alter(2); } 替換掉下面的2個(gè) a = undefined ,a = function a(){ alter(4); } 又替換掉 a = function a(){ alter(2); } ,最終只剩下 a = function a(){ alter(4); }

預(yù)解析(預(yù)編譯) 后的代碼樣子是這樣的

var a = function a(){ alter(4); }
alert(a);
alert(a);
a = 1
alert(a);
a = 3;
alert(a);
alert(a);
a();

執(zhí)行代碼

就是執(zhí)行的這段代碼,依次從上到下執(zhí)行,最后的 a() 函數(shù)調(diào)用,這時(shí)的 a 已被 表達(dá)式 賦值成 3 ,而報(bào)錯(cuò) a is not a function

全局作用域和局部作用域

再看這段代碼

var a = 1;
function fn1(){
    alert(a);
    var a = 2;
}
fn1();
alert(a);

這里先揭曉答案:

第一個(gè) alert(a) 彈出 undefined

第二個(gè) alert(a) 彈出 1

JavaScript 的作用域只用兩種,一個(gè)是全局的,一個(gè)是函數(shù)的,也稱(chēng)為 全局作用域局部作用域 ;局部作用域 可以訪問(wèn) 全局作用域 。但是 全局作用域 不能訪問(wèn) 局部作用域

同樣用 預(yù)解析(預(yù)編譯) 的方法來(lái)分析這段代碼

預(yù)解析(預(yù)編譯) 全局作用域

// 第1行,遇到 var 關(guān)鍵字,解析到全局的頭部
a = undefined
// 第2行,遇到 function 關(guān)鍵字,解析到全局的頭部
fn1 = function fn1(){
    alert(a);
    var a = 2;
}
// 第3行,沒(méi)有遇到關(guān)鍵字,不解析
// 第4行,沒(méi)有遇到關(guān)鍵字,不解析

開(kāi)始執(zhí)行代碼

第1行,遇到表達(dá)式 a = 1, a 被賦值成 1
第6行,遇到函數(shù)調(diào)用 fn1() ,開(kāi)始 預(yù)解析(預(yù)編譯) 局部

預(yù)解析(預(yù)編譯) 局部作用域

// 第3行,沒(méi)有遇到關(guān)鍵字,不解析
// 第4行,遇到 var 關(guān)鍵字,解析到局部
a = undefined

開(kāi)始執(zhí)行 局部 代碼

第3行,彈出 undefined
第4行,遇到表達(dá)式,把局部 a 改成 2

局部執(zhí)行完成,繼續(xù)執(zhí)行全局

第7行,彈出 1 ,因?yàn)槿趾途植渴莾蓚€(gè)獨(dú)立的作用域

作用域鏈

如果,把上面?代碼,稍作修改

var a = 1;
function fn1(){
    alert(a);
    a = 2;
}
fn1();
alert(a);

去掉了 function 里的 var ,結(jié)果就會(huì)不一樣
這次,輸出的是:

第一個(gè) alert 彈出 1

第二個(gè) alert 彈出 2

因?yàn)樵诮馕鼍植渴菦](méi)有發(fā)現(xiàn) var a ,如是在執(zhí)行時(shí),就會(huì)去全局查找,找到了全局的 a = 1 ,所以 第一個(gè) alert 彈出 1 ,而不是 undefined ,這個(gè)就是 作用域連

匿名函數(shù)表達(dá)式、具名函數(shù)表達(dá)式

在來(lái)看看這段代碼?

var a = 3;
function fn() {
    foo();
    function foo() {
        console.log(1);
    }
    foo();
    var foo = function() {
        console.log(2);
    };
    foo();
    var bar = function foo() {
        if(a > 3) return;
        console.log(++a);
        foo();
    };
    foo();
    bar();
}
fn();

先揭曉答案:

第1個(gè) foo() 輸出的是 1

第2個(gè) foo() 輸出的是 1

第3個(gè) foo() 輸出的是 2

第4個(gè) foo() 輸出的是 2

最后的 bar() 輸出的是 4

以上代碼包含了 函數(shù)聲明 、 匿名函數(shù)表達(dá)式 、 具名函數(shù)表達(dá)式 ,匿名函數(shù)表達(dá)式具名函數(shù)表達(dá)式 是把函數(shù)體賦值給一個(gè)變量,因此擁有和變量相同的特性 變量提升 ,而 具名函數(shù)表達(dá)式 的函數(shù)名只能在函數(shù)內(nèi)部使用。

了解了這些,再來(lái)分析段代碼

全局預(yù)解析

a = undefined
fn = function fn(){
    ...
}

執(zhí)行代碼

第1行,遇到表達(dá)式,把 a 的值改變成3
最后行,遇到函數(shù)調(diào)用,重新 預(yù)解析 局部

局部預(yù)解析

// 第4行,遇到 function 關(guān)鍵字,解析到局部的頭部
foo = function(){
    console.log(1);
}
// 第8行,遇到 var 關(guān)鍵字,解析到局部的頭部
foo = undefined
// 第12行,遇到 var 關(guān)鍵字,解析到局部的頭部
bar = undefined

由于有兩個(gè)同名變量 foo ,遵循 function 優(yōu)先 var 因此, foo = undefined 被干掉

局部預(yù)解析 完之后的代碼應(yīng)該是這個(gè)樣子?

var a = 3
function fn() {
    var foo = function foo() {
        console.log(1);
    }
    var bar;
    foo();
    foo();
    foo = function foo() {
        console.log(2);
    };
    foo();
    bar = function foo() {
        if(a > 3) return;
        console.log(++a);
        foo();
    };
    foo();
    bar();
}
fn();

執(zhí)行局部代碼

第1個(gè) foo() 輸出的是 1
第2個(gè) foo() 輸出的是 1
第3個(gè) foo() 輸出的是 2
第4個(gè) foo() 輸出的是 2

注意 這個(gè) foo() 輸出的是上面 foo = function foo() {console.log(2);} 的內(nèi)容,因?yàn)?具名函數(shù)表達(dá)式 的函數(shù)名只能在函數(shù)內(nèi)部使用,在外部無(wú)法訪問(wèn)。

最后的 bar() 輸出的是 4

這里才是輸出 function foo() {if(a > 3) return;console.log(++a);foo();} 里的內(nèi)容,而且,這個(gè)函數(shù)體內(nèi)也有自身的調(diào)用,結(jié)果 a 變量 +1 ,說(shuō)明可以調(diào)用,其實(shí),可以用 bar.name 輸出的就是 foo

所以,注意:

bar = function foo() , 不要用這種寫(xiě)法

不推薦使用 匿名函數(shù)表達(dá)式 ,有以下 ? 幾個(gè)缺點(diǎn)

在追蹤棧中沒(méi)函數(shù)名,調(diào)試?yán)щy

如果需要引用自身,只能用非標(biāo)準(zhǔn)的 arguments.callee(ES5嚴(yán)格模式禁用)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/93951.html

相關(guān)文章

  • 淺談javascript作用

    摘要:理解作用域作用域負(fù)責(zé)收集并維護(hù)由所有聲明的變量組成的集合,等待引擎的查找。當(dāng)遇到時(shí),編譯器會(huì)詢(xún)問(wèn)作用域是否存在變量。詞法作用域就是定義在詞法階段的作用域。但函數(shù)不是唯一的作用域單元。塊作用域?qū)儆谀硞€(gè)代碼塊通常指內(nèi)部。 理解作用域 作用域負(fù)責(zé)收集并維護(hù)由所有聲明的變量組成的集合,等待引擎的查找。 var a = 2; console.log(a); // 2 console.log(b...

    leiyi 評(píng)論0 收藏0
  • 淺談Javascript閉包中作用及內(nèi)存泄漏問(wèn)題

    摘要:將作用域賦值給變量這里的作用域是,而不是將作用域賦值給一個(gè)變量閉包返回瀏覽器中內(nèi)存泄漏問(wèn)題大家都知道,閉包會(huì)使變量駐留在內(nèi)存中,這也就導(dǎo)致了內(nèi)存泄漏。 上一章我們講了匿名函數(shù)和閉包,這次我們來(lái)談?wù)勯]包中作用域this的問(wèn)題。 大家都知道,this對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局就是[object window],如果在對(duì)象內(nèi)部就是指向這個(gè)對(duì)象,而閉包卻是在運(yùn)行...

    source 評(píng)論0 收藏0
  • 淺談JavaScript閉包

    摘要:但是函數(shù)返回了內(nèi)部函數(shù),內(nèi)部函數(shù)會(huì)隨時(shí)訪問(wèn)變量所以垃圾回收機(jī)制是不會(huì)回收函數(shù)的內(nèi)部作用域的,這就是閉包的含義。也就是函數(shù)在定義的詞法作用域以外的地方被調(diào)用,閉包使得函數(shù)可以繼續(xù)訪問(wèn)定義時(shí)的詞法作用域。   初學(xué)JavaScript閉包時(shí),閉包這個(gè)概念在我眼里及其的神秘,也不知道這個(gè)東西在講什么,尤其某些地方的閉包概念定義的非常抽象,屬于那種本來(lái)你可能明白這個(gè)概念,看了反而又把你給繞糊涂...

    hsluoyz 評(píng)論0 收藏0
  • 云天視角-淺談閉包

    摘要:函數(shù)在執(zhí)行的時(shí)候執(zhí)行函數(shù),將當(dāng)前的變量對(duì)象由于當(dāng)前的環(huán)境是函數(shù),所以將其活動(dòng)對(duì)象作為變量對(duì)象添加到作用域鏈的前端。此時(shí),由于在執(zhí)行,而作用域鏈也存在,所以可以在作用域鏈上進(jìn)行查找,去訪問(wèn)的變量。 一、現(xiàn)狀 閉包是jser繞不過(guò)的坎,一直在都在說(shuō),套用 simpson 的話來(lái)說(shuō):JavaScript中閉包無(wú)處不在,你只需要能夠識(shí)別并擁抱它。 閉包是基于詞法作用域書(shū)寫(xiě)代碼時(shí)的自然結(jié)果,你甚...

    nanfeiyan 評(píng)論0 收藏0
  • 淺談JavaScript中的閉包

    摘要:在內(nèi)部,理所當(dāng)然能訪問(wèn)到局部變量,但當(dāng)作為的返回值賦給外的全局變量時(shí),神奇的事情發(fā)生了在全局作用域中訪問(wèn)到了,這就是閉包。而閉包最神奇的地方就是能在一個(gè)函數(shù)外訪問(wèn)函數(shù)中的局部變量,把這些變量用閉包的形式放在函數(shù)中便能避免污染。 一、閉包是什么? 《JavaScript高級(jí)程序設(shè)計(jì)》中寫(xiě)道:閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù),如果用下定義的觀點(diǎn)看,這句話就是說(shuō)閉包是函數(shù),我...

    Riddler 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<