欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript變量函數(shù)聲明提升深刻理解

 更新時(shí)間:2022年06月01日 09:23:06   作者:天行無(wú)忌  
本文主要介紹了Javascript變量函數(shù)聲明提升深刻理解,Javascript變量函數(shù)聲明提升Hoisting是在Javascript中執(zhí)行上下文工作方式的一種認(rèn)識(shí),更多相關(guān)知識(shí)需要的小伙伴可以參考下面文章詳細(xì)內(nèi)容

前言:

Javascript變量函數(shù)聲明提升(Hoisting)是在 Javascript 中執(zhí)行上下文工作方式的一種認(rèn)識(shí)(也可以說(shuō)是一種預(yù)編譯),從字面意義上看,“變量提升”意味著變量和函數(shù)的聲明會(huì)在物理層面移動(dòng)到代碼的最前面,在代碼里的位置是不會(huì)動(dòng)的,而是在編譯階段被放入內(nèi)存中會(huì)和代碼順序不一樣。變量函數(shù)聲明提升雖然對(duì)于實(shí)際編碼影響不大,特別是現(xiàn)在ES6的普及,但作為前端算是一個(gè)基礎(chǔ)知識(shí),必須掌握的,是很多大廠的前端面試必問(wèn)的知識(shí)點(diǎn)之一。在這里分享,不是什么新鮮的內(nèi)容,只是作為一個(gè)自己的學(xué)習(xí)筆記,加速對(duì)其的理解。

變量知道是ES5中的 var 和 function 中的產(chǎn)物,ES6中的 let 、 const 則不存在有變量提升。

變量提升

JavaScript引擎的工作方式是先解析代碼,獲取所有聲明的變量和函數(shù),然后再一行一行地運(yùn)行。這造成的結(jié)果,就是所有的變量的聲明語(yǔ)句,都會(huì)被提升到代碼的頭部,這就叫做變量提升(Hoisting)。

這里說(shuō)的變量聲明,包括函數(shù)的聲明,接下來(lái)看看代碼:

function hoistingVariable() {
    if (!devpoint) {
        var devpoint = 1;
    }
    console.log(devpoint);
}
hoistingVariable();

// 下面是輸出結(jié)果
// 1

變量所處的作用域?yàn)楹瘮?shù)體內(nèi),解析的時(shí)候查找該作用域中的聲明的變量,devpoint在if雖然未聲明,根據(jù)變量提升規(guī)則,變量的聲明提升到函數(shù)的第一行,但未賦值。

實(shí)際的效果等同于下面的代碼:

function hoistingVariable() {
    var devpoint;
    if (!devpoint) {
        devpoint = 1;
    }
    console.log(devpoint);
}
hoistingVariable();

接下再增加一些迷惑的代碼,如下:

var devpoint = "out";
function hoistingVariable() {
    var devpoint;
    if (!devpoint) {
        devpoint = "in";
    }
    console.log(devpoint);
}
hoistingVariable();
console.log(devpoint);

// 下面是輸出結(jié)果
// in
// out

對(duì)于同名變量聲明,個(gè)人理解是先找作用域,就近原則,函數(shù)體內(nèi)聲明(前提是有聲明 var ),就只找函數(shù)內(nèi)查找,并不受函數(shù)外聲明的影響。

把上面函數(shù)體內(nèi)的聲明語(yǔ)句去掉,輸出情況也就不一樣。

var devpoint = "out";
function hoistingVariable() {
    if (!devpoint) {
        devpoint = "in";
    }
    console.log(devpoint);
}
hoistingVariable();
console.log(devpoint);

// 下面是輸出結(jié)果
// out
// out

函數(shù)體內(nèi)聲明語(yǔ)句去掉后,這是就需要去函數(shù)體外找聲明,根據(jù)這一條,函數(shù)外聲明并賦值了,函數(shù)體內(nèi)的 if 語(yǔ)句就不會(huì)執(zhí)行。

下面代碼調(diào)整了賦值的順序,代碼如下:

var devpoint;
function hoistingVariable() {
    if (!devpoint) {
        devpoint = "in";
    }
    console.log(devpoint);
}
devpoint = "out";
hoistingVariable();
console.log(devpoint);

// 下面是輸出結(jié)果
// out
// out

根據(jù)上面說(shuō)的,函數(shù)體內(nèi)的變量是外部聲明的,但未賦值,函數(shù)是提升了,并為執(zhí)行。在函數(shù)執(zhí)行前賦值給devpoint,再執(zhí)行就變成了out

函數(shù)提升

上面介紹過(guò),變量提升,同樣包括函數(shù)的聲明,不同方式的函數(shù)聲明,執(zhí)行也有所不同。這種問(wèn)題就是直接上代碼。

function hoistingFun() {
    hello();
    function hello() {
        console.log("hello");
    }
}
hoistingFun();

// 下面是輸出結(jié)果
// hello

上面的代碼能夠正常運(yùn)行是因?yàn)楹瘮?shù)聲明被提升,函數(shù) hello 被提升到頂部,運(yùn)行效果跟下面代碼一致:

function hoistingFun() {
    function hello() {
        console.log("hello");
    }
    hello();
}
hoistingFun();

// 下面是輸出結(jié)果
// hello

如果在同一個(gè)作用域中對(duì)同一個(gè)函數(shù)進(jìn)行聲明,后面的函數(shù)會(huì)覆蓋前面的函數(shù)聲明。

function hoistingFun() {
    hello();
    function hello() {
        console.log("hello");
    }

    function hello() {
        console.log("hello2");
    }
}
hoistingFun();

// 下面是輸出結(jié)果
// hello2

兩個(gè)函數(shù)聲明都被提升了,按照聲明的順序,后面的聲明覆蓋前面的聲明。

函數(shù)聲明常見(jiàn)的方式有兩種,還有一種是匿名函數(shù)表達(dá)式聲明方式,這種方式可以視為是變量的聲明來(lái)處理,當(dāng)作用域中有函數(shù)聲明和變量聲明時(shí),函數(shù)聲明的優(yōu)先級(jí)最高,將上面的代碼更改后,結(jié)果就不一樣了,

如下:

function hoistingFun() {
    hello();
    function hello() {
        console.log("hello");
    }

    var hello = function () {
        console.log("hello2");
    };
}
hoistingFun();

// 下面是輸出結(jié)果
// hello

上面的代碼,編譯邏輯如下:

function hoistingFun() {
    function hello() {
        console.log("hello");
    }
    hello();

    hello = function () {
        console.log("hello2");
    };
}
hoistingFun();
// 下面是輸出結(jié)果
// hello

接下來(lái)再來(lái)看下,外部使用變量聲明,函數(shù)體內(nèi)使用函數(shù)聲明的示例:

var hello = 520;

function hoistingFun() {
    console.log(hello);

    hello = 521;
    console.log(hello);
    function hello() {
        console.log("hello");
    }
}
hoistingFun();
console.log(hello);
// 下面是輸出結(jié)果
// [Function: hello]
// 521
// 520

上面說(shuō)過(guò),在函數(shù)體內(nèi)聲明過(guò)的變量或者函數(shù),只作用于函數(shù)體內(nèi),受限于函數(shù)體內(nèi),不受外部聲明的影響,相當(dāng)于函數(shù)體內(nèi)作用域與外部隔離。

上面代碼的編譯后的邏輯如下:

var hello = 520;
function hoistingFun() {
    function hello() {
        console.log("hello");
    }
    console.log(hello);

    hello = 521;
    console.log(hello);
}
hoistingFun();
console.log(hello);

在變量聲明中,函數(shù)的優(yōu)先權(quán)最高,永遠(yuǎn)提升到作用域最頂部,然后才是函數(shù)表達(dá)式和變量的執(zhí)行順序。

來(lái)看下面的代碼:

var hello = 520;
function hello() {
    console.log("hello");
}
console.log(hello);
// 下面是輸出結(jié)果
// 520

根據(jù)函數(shù)聲明優(yōu)先級(jí)最高的原則,上面代碼的執(zhí)行邏輯如下:

function hello() {
    console.log("hello");
}
hello = 520;
console.log(hello);

為什么要提升?

至于為什么要提升,這里不做詳細(xì)介紹,提供一些參考文章,有興趣的可以去查閱

最佳實(shí)踐

現(xiàn)代Javascript中,已經(jīng)有很多方式避免變量提升帶來(lái)的問(wèn)題,使用letconst替代var,使用eslint等工具避免變量重復(fù)定義,在一些前端開(kāi)發(fā)團(tuán)隊(duì)中,可以針對(duì)團(tuán)隊(duì)做一些規(guī)范化的腳手架,如項(xiàng)目初始化強(qiáng)制項(xiàng)目的目錄、eslint的最佳配置等,用程序規(guī)范的過(guò)程比人督促要靠譜。

下面的代碼可以看到const 和 var 聲明的變量的區(qū)別,const 聲明的變量不會(huì)提升,具體的區(qū)別可以查閱《javascript 變量聲明 var,let,const 的區(qū)別

console.log("1a", myTitle1);
if (1) {
    console.log("1b", myTitle1);
    var myTitle1 = "devpoint";
}
if (1) {  // 這里的代碼是有錯(cuò)誤無(wú)法執(zhí)行
    console.log("3c", myTitle2);
    const myTitle2 = "devpoint";
}
// 下面是輸出結(jié)果
// 1a undefined
// 1b undefined

總結(jié)

通過(guò)自我學(xué)習(xí)變量函數(shù)提升,加深了對(duì)其理解,對(duì)于前端面試所涉及的類似問(wèn)題可以自信的給出答案,算是一種收獲。

到此這篇關(guān)于Javascript變量函數(shù)聲明提升加深理解的文章就介紹到這了,更多相關(guān)JS變量聲明內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論