第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

JavaScript中函數(shù)作為另一個(gè)函數(shù)的參數(shù)的時(shí)候它存在于哪個(gè)作用域

JavaScript中函數(shù)作為另一個(gè)函數(shù)的參數(shù)的時(shí)候它存在于哪個(gè)作用域

BIG陽(yáng) 2018-10-19 10:15:06
一直對(duì)函數(shù)作為參數(shù)被傳遞進(jìn)另外一個(gè)函數(shù)理解的不是很清除。先看下這段代碼吧:function test(fn){    var bar = 1;    fn();}var bar = 99;test(function foo(){    console.log(bar);});console.log(foo);先說(shuō)下結(jié)果為99和foo is not defined。在《你不知道的JavaScript》一書中有這么一句話:無(wú)論函數(shù)在哪里被調(diào)用,也無(wú)論它如何被調(diào)用,它的詞法作用域都只由函數(shù)被聲明時(shí)所處的位置決定。所以我的問(wèn)題是這樣的:上面代碼中test函數(shù)的參數(shù)foo函數(shù)是函數(shù)表達(dá)式對(duì)吧?也算是函數(shù)聲明吧?代碼中的foo函數(shù)到底存在于哪個(gè)作用域里面呢?我最開始以為console.log(bar)的結(jié)果是99,說(shuō)明了這個(gè)foo函數(shù)存在于全局作用域內(nèi)而不是test函數(shù)作用域內(nèi)(如果在test函數(shù)的作用域內(nèi)結(jié)果就該為1了吧),可是最后的console.log(foo)的結(jié)果又是foo is not defined。。困惑了很久。。望解答~
查看完整描述

1 回答

?
心有法竹

TA貢獻(xiàn)1866條經(jīng)驗(yàn) 獲得超5個(gè)贊

JS中對(duì)于函數(shù)的聲明語(yǔ)法在標(biāo)準(zhǔn)中就有兩種不同的語(yǔ)法樣式,其一稱為函數(shù)聲明樣式,另一個(gè)是函數(shù)表達(dá)式樣式,在標(biāo)準(zhǔn)中也寫得很簡(jiǎn)略,像下面這樣,上面的是函數(shù)聲明樣式,下面則是函數(shù)表達(dá)式,opt記號(hào)代表的是可選的,也就是可有可無(wú)的意思:

FunctionDeclaration :function Identifier ( FormalParameterList opt ){ FunctionBody }

FunctionExpression :function Identifier opt ( FormalParameterList opt ){ FunctionBody }

所以在函數(shù)表達(dá)式這種樣式,函數(shù)的識(shí)別名是可以不需要有的,但它因?yàn)槭莻€(gè)表達(dá)式,可以賦給另一個(gè)變量當(dāng)值來(lái)看待,所以才會(huì)有像var f = function(){ return 23 }的這種寫法,真正在函數(shù)調(diào)用時(shí)是用前面的變量識(shí)別名稱f,而不是額外的那個(gè)可有可無(wú)的函數(shù)識(shí)別名稱。如果充分區(qū)分出函數(shù)聲明函數(shù)表達(dá)式的兩種不同樣式,在文中最好以函式創(chuàng)建這字詞來(lái)說(shuō)明函數(shù)聲明或函數(shù)表達(dá)式的這兩種語(yǔ)句較佳。

那要分辨何者是函數(shù)聲明又何者是函式表達(dá)式?最簡(jiǎn)單的方式就是看語(yǔ)句的開頭,在單一個(gè)語(yǔ)句中以function作為該語(yǔ)句開頭的函數(shù),應(yīng)該就是函數(shù)聲明,函式表達(dá)式不會(huì)以function開頭。所以下面的幾例都是函式表達(dá)式而不是函式聲明樣式:

var a = function() {    return 3;
} 
var a = function bar() {    return 3;
}
 
(function sayHello() {
    alert("hello!");
})();

而為何會(huì)有兩種不同的函數(shù)語(yǔ)法樣式,主要是這兩種樣式的用處不同,這有很多不同的應(yīng)用情況。

最明顯的例子是函數(shù)聲明有特殊的提升(hoisting)特性,在同一作用域中的函數(shù)聲明會(huì)先被提升到此作用域的最上面,所以函數(shù)聲明可以寫在代碼文檔的后面,但可以在代碼文檔的上面位置使用。此外,函數(shù)聲明只能在函數(shù)中塊級(jí)或整個(gè)應(yīng)用的全局區(qū)中使用,它沒(méi)辦法在其他的塊級(jí)中使用,例如像if、for等的花括號(hào)({})中。而在某些情況下,當(dāng)需要把函數(shù)整體塊級(jí)作為一種值,用來(lái)當(dāng)其他函數(shù)的傳參或返回時(shí),例如回調(diào)函數(shù)的語(yǔ)法結(jié)構(gòu),就是要使用函式表達(dá)式的樣式才可以達(dá)到。當(dāng)然,基本上這兩者看起來(lái)好像都是長(zhǎng)得一樣,實(shí)際上在執(zhí)行階段的運(yùn)作并不相同。

帶有名稱的函數(shù)表達(dá)式,有個(gè)專用語(yǔ)稱之為"具名函數(shù)表達(dá)式"(Named function expressions,NFE),這個(gè)函數(shù)的識(shí)別名,它的作用域到底是在什么地方,答案是在函數(shù)的主體(FunctionBody)內(nèi)部。原因當(dāng)然它只是個(gè)原本就可有可無(wú)的"代理"函數(shù)名,真正的這函數(shù)識(shí)別名稱是被賦值的那個(gè)變量識(shí)別名。

正常情況下,你只能在函數(shù)表述式中的主體中使用這個(gè)"代理函數(shù)名",這也是符合標(biāo)準(zhǔn)的規(guī)定,如下面的例子:

var f = function foo(){  return typeof foo; 
};typeof foo; // "undefined"f(); // "function"

那么又為何要使用這個(gè)"代理函數(shù)名",不是可有可無(wú)的嗎?

因?yàn)檫@個(gè)名稱在調(diào)試時(shí),可以明確地在呼叫堆疊中看到,如果是不加這名稱,也就是"匿名函數(shù)表達(dá)式"在調(diào)試時(shí)是看不準(zhǔn)是呼叫什么的。這使得調(diào)試時(shí)多了一些便利,所以它會(huì)被用在這個(gè)情況下。

比較特別的情況是在IE8以前的版本中,它里面的JS引擎并不是現(xiàn)在的標(biāo)準(zhǔn)ECMAScript規(guī)范,而是JScript 5.8。IE8并沒(méi)有設(shè)計(jì)這個(gè)封閉作用域,來(lái)界定出函數(shù)表達(dá)式的作用域,而且,在IE8中認(rèn)為這種"具名函數(shù)表達(dá)式",相等于函數(shù)聲明。

以上的資料主要參考Named function expressions demystifiedFunction Declarations vs. Function Expressions


后面針對(duì)題目本身提供一些解答:

上面代碼中test函數(shù)的參數(shù)foo函數(shù)是函數(shù)表達(dá)式對(duì)吧?也算是函數(shù)聲明吧?

函數(shù)表達(dá)式而不是函數(shù)聲明,這是依照ECMAScript標(biāo)準(zhǔn)的說(shuō)明。只是它有帶函數(shù)名,是上面說(shuō)的"具名函數(shù)表達(dá)式"(NFE)。

代碼中的foo函數(shù)到底存在于哪個(gè)作用域里面呢?

函數(shù)表達(dá)式的函數(shù)定義塊級(jí)作用域里,也就是函數(shù)的主體(FunctionBody)內(nèi)部,上面有例子。但這有例外情況,在IE8以前的IE瀏覽器,這代碼應(yīng)該是會(huì)如同函數(shù)聲明樣式一樣的執(zhí)行結(jié)果。


另一個(gè)問(wèn)題忘了說(shuō)明,補(bǔ)充一下。

全域中有一個(gè)bar=99變量,在test函數(shù)中的區(qū)塊中也有聲明一個(gè)bar=1,那么如果在傳參中是以函數(shù)類型傳入test函數(shù),有存取bar如console.log(bar),為何答案是99而不是1?

主要是因?yàn)閭鲄⒌淖饔糜蚴窃谌肿饔糜?,并非函?shù)的作用域之中。也就是說(shuō)像下面的代碼:

test(function foo(){
    console.log(bar);});

相等于下面的代碼:

var f = function foo(){
    console.log(bar);
}test(f);

也就是說(shuō)在本例子中,test的傳參在傳入后,然后被調(diào)用,里面要作什么事,已經(jīng)可以決定了結(jié)果,也就是相當(dāng)于:

var bar = 99;var f = function foo(){    console.log(99); // bar在全局中已賦值為99}

test(f);

上面說(shuō)的概念雖然會(huì)有點(diǎn)怪異,在這個(gè)例子你可以把f這個(gè)函數(shù),當(dāng)成只是稍晚些打印到控制臺(tái)的一種變量而已。

因?yàn)楹芴貏e的是,這個(gè)f函數(shù),它并沒(méi)有傳參,也沒(méi)有返回,單純只是打印bar變量,這個(gè)bar變量如果要能有值,只能從函數(shù)所能存取得到的作用域而來(lái),而且是以函數(shù)聲明的主體上下文作用域?yàn)橹鳌?/p>

例子中的傳參的作用域是位于全局作用域,所以只能存取得到全局的那個(gè)var bar = 99變量。

會(huì)讓人誤解的是這個(gè)test函數(shù)中的寫法:

function test(fn){    var bar = 1;
    fn();
}

有可能會(huì)直覺(jué)得認(rèn)定,應(yīng)該是相當(dāng)于下面的寫法:

function test(function foo(){
    console.log(bar); 
}){    var bar = 1;
    foo();
}

所以它的結(jié)果應(yīng)該是:

console.log(1)

但結(jié)果不是上面那樣,實(shí)際上這相當(dāng)于下面的例子,因?yàn)閒函數(shù)不需要傳參,所以相等于直接在test函數(shù)中調(diào)用而已:

var f = function foo(){    console.log(99); // bar在全局中已賦值為99}function test(){    var bar = 1;
    f();
}

除非f函數(shù)的內(nèi)容,是定義在test函數(shù)的區(qū)塊之中時(shí),才有可能得到1的打印結(jié)果,像下面這樣:

function test(){    var bar = 1;    var f = function foo(){      console.log(bar); // bar相當(dāng)于1
    }
    f();
}

JS中的作用域,是屬于詞法上的作用域,也就是"靜態(tài)"的作用域,作用域中的變量綁定,在執(zhí)行前就已經(jīng)決定好了,按定義是在編譯期間。在JavaScript: The Definitive Guide這本書中對(duì)作用域的一句說(shuō)明如下:

函數(shù)在調(diào)用(執(zhí)行)時(shí),使用它們被定義(聲明)時(shí)被影響的作用域鏈

這與題中所引用的 你不知道的JavaScript 書中的說(shuō)明是一樣的:

無(wú)論函數(shù)在哪里被調(diào)用,也無(wú)論它如何被調(diào)用,它的詞法作用域都只由函數(shù)被聲明時(shí)所處的位置決定。


查看完整回答
反對(duì) 回復(fù) 2018-11-15
  • 1 回答
  • 0 關(guān)注
  • 630 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)