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

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

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

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

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

1 回答

?
心有法竹

TA貢獻1866條經(jīng)驗 獲得超5個贊

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

FunctionDeclaration :function Identifier ( FormalParameterList opt ){ FunctionBody }

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

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

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

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

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

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

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

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

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

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

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

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

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


后面針對題目本身提供一些解答:

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

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

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

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


另一個問題忘了說明,補充一下。

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

主要是因為傳參的作用域是在全局作用域,并非函數(shù)的作用域之中。也就是說像下面的代碼:

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

相等于下面的代碼:

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

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

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

test(f);

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

因為很特別的是,這個f函數(shù),它并沒有傳參,也沒有返回,單純只是打印bar變量,這個bar變量如果要能有值,只能從函數(shù)所能存取得到的作用域而來,而且是以函數(shù)聲明的主體上下文作用域為主。

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

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

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

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

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

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

console.log(1)

但結(jié)果不是上面那樣,實際上這相當(dāng)于下面的例子,因為f函數(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ū)塊之中時,才有可能得到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這本書中對作用域的一句說明如下:

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

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

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


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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