成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JS基礎(chǔ)篇--函數(shù)聲明與定義,作用域,函數(shù)聲明與表達(dá)式的區(qū)別

TerryCai / 3567人閱讀

摘要:在中,有四種方式可以讓命名進入到作用域中按優(yōu)先級語言定義的命名比如或者,它們在所有作用域內(nèi)都有效且優(yōu)先級最高,所以在任何地方你都不能把變量命名為之類的,這樣是沒有意義的形式參數(shù)函數(shù)定義時聲明的形式參數(shù)會作為變量被至該函數(shù)的作用域內(nèi)。

Scoping & Hoisting

例:

var a = 1;

function foo() {
    if (!a) {
        var a = 2;
    }
    alert(a);
};

foo();

上面這段代碼在運行時會產(chǎn)生什么結(jié)果?

盡管對于有經(jīng)驗的程序員來說這只是小菜一碟,不過我還是順著初學(xué)者常見的思路做一番描述:

創(chuàng)建了全局變量 a,定義其值為 1

創(chuàng)建了函數(shù) foo

在 foo 的函數(shù)體內(nèi),if 語句將不會執(zhí)行,因為 !a 會將變量 a 轉(zhuǎn)變成布爾的假值,也就是 false

跳過條件分支,alert 變量 a,最終的結(jié)果應(yīng)該是輸出 1

嗯,看起來無懈可擊的推理啊,但讓人驚訝的是:答案竟然是 2!為什么?

別著急,我會解釋給你聽。首先我要告訴你這不是什么錯誤,而是 JavaScript 語言解釋器的一個(非官方的)特性,某人(Ben Cherry)把這個特性叫做:Hoisting(目前尚未有標(biāo)準(zhǔn)的翻譯,比較常見的是提升)。

聲明與定義

為了理解 Hoisting,我們先來看一個簡單的情況:

var a = 1;

你是否想過,上面這句代碼在運行的時候到底發(fā)生了什么?
你是否知道,就這句代碼而言,“聲明變量 a” 和 “定義變量 a”這兩個說法哪一個才是正確的?

下例叫做 “聲明變量”:

var a;

下例叫做 “定義變量”:

var a = 1;

聲明:是指你聲稱某樣?xùn)|西的存在,比如一個變量或一個函數(shù);但你沒有說明這樣?xùn)|西到底是什么,僅僅是告訴解釋器這樣?xùn)|西存在而已;
定義:是指你指明了某樣?xùn)|西的具體實現(xiàn),比如一個變量的值是多少,一個函數(shù)的函數(shù)體是什么,確切的表達(dá)了這樣?xùn)|西的意義。
總結(jié)一下:

var a;            // 這是聲明
a = 1;            // 這是定義(賦值)
var a = 1;        // 合二為一:聲明變量的存在并賦值給它

重點來了:當(dāng)你以為你只做了一件事情的時候(var a = 1),實際上解釋器把這件事情分解成了兩個步驟,一個是聲明(var a),另一個是定義(a = 1)。
這和 Hoisting 有何關(guān)系?

回到最開始的那個令人困惑的例子,我告訴你解釋器是如何分析你的代碼的:

var a;
a = 1;

function foo() {
    var a;        // 關(guān)鍵在這里
    if (!a) {
        a = 2;
    }
    alert(a);     // 此時的 a 并非函數(shù)體外的那個全局變量
}

如代碼所示,在進入函數(shù)體后解釋器聲明了新的變量 a,而無論 if 語句的條件如何,都將為新的變量 a 賦值為 2。你若不相信可以在函數(shù)體外面 alert(a),然后再執(zhí)行 foo() 對比一下結(jié)果就知道了。

Scoping(作用域)

有人可能會問了:“為什么不是在 if 語句內(nèi)聲明變量 a?”

因為 JavaScript 沒有塊級作用域(Block Scoping),只有函數(shù)作用域(Function Scoping),所以說不是看見一對花括號{} 就代表產(chǎn)生了新的作用域,和 C 不一樣!

當(dāng)解析器讀到 if 語句的時候,它發(fā)現(xiàn)此處有一個變量聲明和賦值,于是解析器會將其聲明提升至當(dāng)前作用域的頂部(這是默認(rèn)行為,并且無法更改),這個行為就叫做 Hoisting。

OK,大家都懂了,你懂了嗎……

懂了不代表就會用了,就拿最開始的例子來說,如果我就是想要 alert(a) 出那個 1 可咋整呢?

創(chuàng)建新的作用域

alert(a) 在執(zhí)行的時候,會去尋找變量 a 的位置,它從當(dāng)前作用域開始向上(或者說向外)一直查找到頂層作用域為止,若是找不到就報 undefined

因為在 alert(a) 的同級作用域里,我們再次聲明了本地變量 a,所以它報 2;所以我們可以把本地變量 a 的聲明向下(或者說向內(nèi))移動,這樣 alert(a) 就找不到它了。

記?。篔avaScript 只有函數(shù)作用域!

var a = 1;

function foo() {
    if (!a) {
        (function() {        // 這是上一篇說到過的 IIFE,它會創(chuàng)建一個新的函數(shù)作用域
            var a = 2;       // 并且該作用域在 foo() 的內(nèi)部,所以 alert 訪問不到
        }());                // 不過這個作用域可以訪問上層作用域哦,這就叫:“閉包”
    };
    alert(a);
};

foo();

你或許在無數(shù)的 JavaScript 書籍和文章里讀到過:“請始終保持作用域內(nèi)所有變量的聲明放置在作用域的頂部”,現(xiàn)在你應(yīng)該明白為什么有此一說了吧?因為這樣可以避免 Hoisting 特性給你帶來的困擾(我不是很情愿這么說,因為 Hoisting 本身并沒有什么錯),也可以很明確的告訴所有閱讀代碼的人(包括你自己)在當(dāng)前作用域內(nèi)有哪些變量可以訪問。但是,變量聲明的提升并非 Hoisting 的全部。在 JavaScript 中,有四種方式可以讓命名進入到作用域中(按優(yōu)先級):

語言定義的命名:比如 this 或者 arguments,它們在所有作用域內(nèi)都有效且優(yōu)先級最高,所以在任何地方你都不能把變量命名為 this 之類的,這樣是沒有意義的

形式參數(shù):函數(shù)定義時聲明的形式參數(shù)會作為變量被 hoisting至該函數(shù)的作用域內(nèi)。所以形式參數(shù)是本地的,不是外部的或者全局的。當(dāng)然你可以在執(zhí)行函數(shù)的時候把外部變量傳進來,但是傳進來之后就是本地的了

函數(shù)聲明:函數(shù)體內(nèi)部還可以聲明函數(shù),不過它們也都是本地的了

變量聲明:這個優(yōu)先級其實還是最低的,不過它們也都是最常用的

另外,還記得之前我們討論過 聲明 和 定義 的區(qū)別吧?當(dāng)時我并沒有說為什么要理解這個區(qū)別,不過現(xiàn)在是時候了,記?。?/p>

Hosting 只提升了命名,沒有提升定義

這一點和我們接下來要講到的東西息息相關(guān),請看:

函數(shù)聲明與函數(shù)表達(dá)式的差別

先看兩個例子:

function test() {
    foo();

    function foo() {
        alert("我是會出現(xiàn)的啦……");
    }
}

test();
function test() {
    foo();

    var foo = function() {
        alert("我不會出現(xiàn)的哦……");
    }
}

test();

同學(xué),在了解了 Scoping & Hoisting 之后,你知道怎么解釋這一切了吧?

在第一個例子里,函數(shù) foo 是一個聲明,既然是聲明就會被提升(我特意包裹了一個外層作用域,因為全局作用域需要你的想象,不是那么直觀,但是道理是一樣的),所以在執(zhí)行 foo() 之前,作用域就知道函數(shù) foo 的存在了。這叫做函數(shù)聲明(Function Declaration),函數(shù)聲明會連通命名和函數(shù)體一起被提升至作用域頂部。

然而在第二個例子里,被提升的僅僅是變量名 foo,至于它的定義依然停留在原處。因此在執(zhí)行 foo() 之前,作用域只知道 foo 的命名,不知道它到底是什么,所以執(zhí)行會報錯(通常會是:undefined is not a function)。這叫做函數(shù)表達(dá)式(Function Expression),函數(shù)表達(dá)式只有命名會被提升,定義的函數(shù)體則不會。

尾記:Ben Cherry 的原文解釋的更加詳細(xì),只不過是英文而已。我這篇是借花獻佛,主要是更淺顯的解釋給初學(xué)者聽,若要看更多的示例,請移步原作,謝謝。

轉(zhuǎn)載地址:http://segmentfault.com/a/119...

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/86000.html

相關(guān)文章

  • 一道JS面試題所引發(fā)"血案",透過現(xiàn)象尋本質(zhì),再從本質(zhì)看現(xiàn)象

    摘要:一看這二逼就是周杰倫的死忠粉看看控制臺輸出,確實沒錯就是對象。從根本上來說,作用域是基于函數(shù)的,而執(zhí)行環(huán)境是基于對象的例如全局執(zhí)行環(huán)境即全局對象。全局對象全局屬性和函數(shù)可用于所有內(nèi)建的對象。全局對象只是一個對象,而不是類。 覺得本人寫的不算很爛的話,可以登錄關(guān)注一下我的GitHub博客,博客會堅持寫下去。 今天同學(xué)去面試,做了兩道面試題,全部做錯了,發(fā)過來給我看,我一眼就看出來了,因為...

    QiShare 評論0 收藏0
  • JavaScript知識架構(gòu)學(xué)習(xí)路徑(一)- 變量

    摘要:在此,我們首先根據(jù)變量的作用域,將變量劃分為三級,具體是全局變量局部變量和參數(shù)變量。 【摘要】本文是專為JavaScript入門者而總結(jié)的,總體上將JavaScript的基礎(chǔ)部分分成了九大塊,分別是變量、運算符、數(shù)組、流程控制結(jié)構(gòu)、字符串函數(shù)、函數(shù)基礎(chǔ)、DOM操作基礎(chǔ)、文檔對象模型DOM和正則表達(dá)式。 【關(guān)鍵字】變量、運算符、數(shù)組、流程控制結(jié)構(gòu)、函數(shù)、DOM、正則表達(dá)式。 本篇文章的主...

    toddmark 評論0 收藏0
  • JS筆記四:作用、變量(函數(shù))提升

    摘要:變量作用域一個變量的作用域表示這個變量存在的上下文。在這種情況下,僅僅函數(shù)聲明的函數(shù)體被提升到頂部。雖然我們無需用來修飾形式參數(shù),但是形式參數(shù)的確也是變量,并且被自動提升到次高的優(yōu)先級函數(shù)聲明。 關(guān)于作用域,變量提升,函數(shù)提升的個人理解 參考: 阮一峰的JavaScript參考教程2.7函數(shù)部分 思否上一篇關(guān)于作用域,提升的博客 一篇關(guān)于作用域和提升的個人博客 MockingBird...

    FuisonDesign 評論0 收藏0
  • 【連載】前端個人文章整理-從基礎(chǔ)到入門

    摘要:個人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時間了,由于工作比較忙,更新緩慢,后面還是會繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個人前端文章整理 從最開始萌生寫文章的想法,到著手...

    madthumb 評論0 收藏0

發(fā)表評論

0條評論

TerryCai

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<