JavaScript中標(biāo)識(shí)符提升問(wèn)題
JS 存在變量提升,這個(gè)的設(shè)計(jì)其實(shí)是低劣的,或者是語(yǔ)言實(shí)現(xiàn)時(shí)的一個(gè)副作用。它允許變量不聲明就可以訪問(wèn),或聲明在后使用在前。新手對(duì)于此則很迷惑,甚至許多使用JS多年老手也比較迷惑。但在 ES6 加入 let/const 后,變量Hoisting 就不存在了。
一、 變量未聲明,直接使用
function test() {
alert(notDefined);
}
test(); // ?
報(bào)錯(cuò)是自然的

二. 變量聲明在末尾
function test() {
alert(declaredButNotAssigned); // undefined
var declaredButNotAssigned;
}
test();
輸出 undefined, 結(jié)果比上例有所改善,沒(méi)有報(bào)錯(cuò),代碼可以運(yùn)行,但變量值可能不是程序員所期望的。
三、 變量聲明在末尾,同時(shí)給變量賦值
function test() {
alert(declaredAndAssigned); // undefined
var declaredAndAssigned = 1;
}
test();
結(jié)果和 二 相同, 很明顯,并不會(huì)因?yàn)橘x值了就輸出 1。
二、三 都發(fā)生了變量提升(Hoisting),簡(jiǎn)單定義
變量提升: 在指定作用域里,從代碼順序上看是變量先使用后聲明,但運(yùn)行時(shí)變量的 “可訪問(wèn)性” 提升到當(dāng)前作用域的頂部,其值為 undefined ,沒(méi)有 “可用性”。
這里強(qiáng)調(diào) “代碼順序” 和 “運(yùn)行順序”,是因?yàn)槎鄶?shù)時(shí)候我們寫(xiě)的代碼都是順序執(zhí)行的,即 “代碼順序” 和 “運(yùn)行順序” 是一致的。這也符合人的大腦的思維過(guò)程。比如有過(guò) C語(yǔ)言 經(jīng)驗(yàn)的程序員
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
}
兩句代碼,先聲明整數(shù)型 x, 再輸出。代碼順序和運(yùn)行順序是一致的,即正常運(yùn)行。
如果順序反過(guò)來(lái)
#include <stdio.h>
int main() {
printf("%d, ", x); // error
int x = 1;
}
此時(shí),編譯都不能通過(guò)了。但JS里可以反過(guò)來(lái)寫(xiě),見(jiàn)二、三。
因此,有類(lèi) C語(yǔ)言 經(jīng)驗(yàn)的程序員,都很清楚變量需要 先聲明后使用,不然會(huì)報(bào)錯(cuò)。而到了JS里,有 變量提升 現(xiàn)象,可以 先使用后聲明,C 的經(jīng)驗(yàn)用到 JS 里迷惑便出現(xiàn)了。
四、 函數(shù)表達(dá)式也存在變量提升
function test() {
alert(func); // undefined
var func = function() {};
}
test();
但如果想使用這個(gè) func,則無(wú)可能
function test() {
alert(func); // undefined
func(); // 報(bào)異常
var func = function() {};
}
test();
結(jié)果func 是 undefined,調(diào)用 func 則會(huì)報(bào)異常。 在上面的定義中提到了 可訪問(wèn)性 和 可用性 對(duì)應(yīng)如下語(yǔ)句。
可訪問(wèn)性:alert(func),輸出 undefined,可以運(yùn)行,可以訪問(wèn) func。
可用性: func(), 報(bào)異常,不能正常調(diào)用 func,表示無(wú)可用性。
二、三、四 都是使用 var 聲明的變量,JS 里函數(shù)聲明也會(huì)存在提升,只是這個(gè) “變量” 比較特殊,它是一個(gè) function 類(lèi)型(可以作為函數(shù)、方法或構(gòu)造器)。它的名字(標(biāo)識(shí)符)也會(huì)提升到當(dāng)前作用域的頂部。
五、函數(shù)聲明的名也會(huì)提升到當(dāng)前作用域頂部
function test() {
alert(f1); // function
f1(); // "called"
function f1() {
alert('called');
}
}
test();
我們看到,聲明 f1 在代碼最末,f1 使用在前,alert(f1) 和 f1() 都正常執(zhí)行,表示 可訪問(wèn)性 和 可用性 都有了。
前面說(shuō)了,變量提升(Hoisting)沒(méi)什么用,屬于語(yǔ)言的低劣設(shè)計(jì),好的習(xí)慣還是 “先聲明后使用”。這個(gè)特性也會(huì)出現(xiàn)在不少大公司面試題里
題1:
// 寫(xiě)出以下代碼的運(yùn)行結(jié)果
var a = 1;
function fn() {
if (!a) {
var a = 2;
}
alert(a); // ?
}
fn();
題2:
// 寫(xiě)出以下代碼的運(yùn)行結(jié)果
var a = 1;
function fn() {
a = 2;
return;
function a() {}
}
fn();
alert(a); // ?
但這一切隨著 ES6 的 let/const 到來(lái)結(jié)束了,ES里除全局變量外,其它都使用 let/const,var 替換成 let 后變量提升就不復(fù)存在了。
function test() {
alert(declaredButNotAssigned1); // 報(bào)異常
alert(declaredButNotAssigned2); // 報(bào)異常
alert(func); // 報(bào)異常
let declaredButNotAssigned1;
let declaredButNotAssigned2 = true;
let func = function() {};
}
test();
這強(qiáng)制程序員養(yǎng)成好的習(xí)慣,變量需要“先聲明再使用”,否則報(bào)錯(cuò)。
以下摘自MDN的關(guān)于let不在發(fā)生變量提升的描述
In ECMAScript 6, let does not hoist the variable to the top of the block. If you reference a variable in a block before the let declaration for that variable is encountered, this results in a ReferenceError, because the variable is in a "temporal dead zone" from the start of the block until the declaration is processed.
用 let 聲明變量后,typeof 也不再安全
if (condition) {
alert(typeof num); // Error!
let num = 100;
}
以前可以用 typeof == 'undefined',來(lái)判斷是否引入了某lib,比如jQuery
// 判斷jQuery是否引入了
if (typeof $ !== 'undefined') {
// do something
}...
jQuery沒(méi)有引入,$ 沒(méi)有聲明,這句也不會(huì)報(bào)錯(cuò)而影響到下面的代碼執(zhí)行,但如果是 let 聲明的就會(huì)報(bào)錯(cuò)了。
以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
- VBS中的標(biāo)識(shí)符(Identifiers)
- 淺析JavaScript中的同名標(biāo)識(shí)符優(yōu)先級(jí)
- C#標(biāo)識(shí)符的使用小結(jié)
- mysql把主鍵定義為自動(dòng)增長(zhǎng)標(biāo)識(shí)符類(lèi)型
- JS在IE下缺少標(biāo)識(shí)符的錯(cuò)誤
- JavaScript實(shí)現(xiàn)生成GUID(全局統(tǒng)一標(biāo)識(shí)符)
- PHP生成不重復(fù)標(biāo)識(shí)符的方法
- IE6/IE7中JavaScript json提示缺少標(biāo)識(shí)符、字符串或數(shù)字問(wèn)題處理
- C#中使用@聲明變量示例(逐字標(biāo)識(shí)符)
- JS中產(chǎn)生標(biāo)識(shí)符方式的演變
相關(guān)文章
canvas實(shí)現(xiàn)動(dòng)態(tài)小球重疊效果
在javascript運(yùn)動(dòng)系列中,詳細(xì)介紹了各種運(yùn)動(dòng),其中就包括碰壁運(yùn)動(dòng)。但是,如果用canvas去實(shí)現(xiàn),卻是另一種思路。本文將詳細(xì)介紹canvas動(dòng)態(tài)小球重疊效果。下面跟著小編一起來(lái)看下吧2017-02-02
JS apply用法總結(jié)和使用場(chǎng)景實(shí)例分析
這篇文章主要介紹了JS apply用法總結(jié)和使用場(chǎng)景,結(jié)合實(shí)例形式分析了JS apply的基本功能、原理、使用方法及操作注意事項(xiàng),需要的朋友可以參考下2020-03-03
完美解決input[type=number]無(wú)法顯示非數(shù)字字符的問(wèn)題
下面小編就為大家?guī)?lái)一篇完美解決input[type=number]無(wú)法顯示非數(shù)字字符的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
javascript中關(guān)于break,continue的特殊用法與介紹
javascript大家所熟知中的for是一個(gè)循環(huán)體,循環(huán)體其中的break和continue也是大家都比較熟悉的功能,相信大家對(duì)它們的用法不會(huì)陌生,本文不是介紹其功能,本文假設(shè)你已經(jīng)熟悉break和continue的語(yǔ)意和用法2012-05-05
24個(gè)解決實(shí)際問(wèn)題的ES6代碼片段(小結(jié))
這篇文章主要介紹了24個(gè)解決實(shí)際問(wèn)題的ES6代碼片段,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
當(dāng)鼠標(biāo)滑過(guò)文本框自動(dòng)選中輸入框內(nèi)容的JS代碼分享
這篇文章主要介紹了當(dāng)鼠標(biāo)滑過(guò)文本框自動(dòng)選中輸入框內(nèi)容的JS代碼,有需要的朋友可以參考一下2013-11-11
基于JavaScript實(shí)現(xiàn)快速轉(zhuǎn)換文本語(yǔ)言(繁體中文和簡(jiǎn)體中文)
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)快速切換正體中文和簡(jiǎn)體中文,需要的朋友可以參考下2016-03-03
VBS通過(guò)WMI監(jiān)視注冊(cè)表變動(dòng)的代碼
似乎有人覺(jué)得用VBS監(jiān)視注冊(cè)表很高級(jí)?使用了WMI事件而已,跟《用VBS監(jiān)視進(jìn)程創(chuàng)建和刪除》一樣2011-10-10

