JavaScript中標識符提升問題,javascript標識

來源:互聯網
上載者:User

JavaScript中標識符提升問題,javascript標識

JS 存在變數提升,這個的設計其實是低劣的,或者是語言實現時的一個副作用。它允許變數不聲明就可以訪問,或聲明在後使用在前。新手對於此則很迷惑,甚至許多使用JS多年老手也比較迷惑。但在 ES6 加入 let/const 後,變數Hoisting 就不存在了。

一、 變數未聲明,直接使用

function test() {  alert(notDefined);}test(); // ?

報錯是自然的

二. 變數聲明在末尾

function test() {  alert(declaredButNotAssigned); // undefined  var declaredButNotAssigned;}test();

輸出 undefined, 結果比上例有所改善,沒有報錯,代碼可以運行,但變數值可能不是程式員所期望的。

三、 變數聲明在末尾,同時給變數賦值

function test() {  alert(declaredAndAssigned); // undefined  var declaredAndAssigned = 1;}test();

結果和 二 相同, 很明顯,並不會因為賦值了就輸出 1。

二、三 都發生了變數提升(Hoisting),簡單定義

變數提升: 在指定範圍裡,從代碼順序上看是變數先使用後聲明,但運行時變數的 “可訪問性” 提升到當前範圍的頂部,其值為 undefined ,沒有 “可用性”。

這裡強調 “代碼順序” 和 “運行順序”,是因為多數時候我們寫的代碼都是順序執行的,即 “代碼順序” 和 “運行順序” 是一致的。這也符合人的大腦的思維過程。比如有過 C語言 經驗的程式員

#include <stdio.h>int main() {  int x = 1;  printf("%d, ", x); // 1}

兩句代碼,先聲明整數型 x, 再輸出。代碼順序和運行順序是一致的,即正常運行。

如果順序反過來

#include <stdio.h>int main() {  printf("%d, ", x); // error  int x = 1;}

此時,編譯都不能通過了。但JS裡可以反過來寫,見二、三。

因此,有類 C語言 經驗的程式員,都很清楚變數需要 先聲明後使用,不然會報錯。而到了JS裡,有 變數提升 現象,可以 先使用後聲明,C 的經驗用到 JS 裡迷惑便出現了。

四、 函數運算式也存在變數提升

function test() {  alert(func); // undefined  var func = function() {};}test();

但如果想使用這個 func,則無可能

function test() {  alert(func); // undefined  func(); // 報異常  var func = function() {};}test();

結果func 是 undefined,調用 func 則會報異常。 在上面的定義中提到了 可訪問性 和 可用性 對應如下語句。

可訪問性:alert(func),輸出 undefined,可以運行,可以訪問 func。

可用性:   func(), 報異常,不能正常調用 func,表示無可用性。

二、三、四 都是使用 var 聲明的變數,JS 裡函式宣告也會存在提升,只是這個 “變數” 比較特殊,它是一個 function 類型(可以作為函數、方法或構造器)。它的名字(標識符)也會提升到當前範圍的頂部。

五、函式宣告的名也會提升到當前範圍頂部

function test() {  alert(f1); // function  f1(); // "called"  function f1() {    alert('called');  }}test();

我們看到,聲明 f1 在代碼最末,f1 使用在前,alert(f1) 和 f1() 都正常執行,表示 可訪問性 和 可用性 都有了。

前面說了,變數提升(Hoisting)沒什麼用,屬於語言的低劣設計,好的習慣還是 “先聲明後使用”。這個特性也會出現在不少大公司面試題裡

題1:

// 寫出以下代碼的運行結果var a = 1;function fn() {  if (!a) {    var a = 2;  }  alert(a); // ?}fn();

題2:

// 寫出以下代碼的運行結果var a = 1;function fn() {  a = 2;  return;  function a() {}}fn();alert(a); // ?

但這一切隨著 ES6 的 let/const 到來結束了,ES裡除全域變數外,其它都使用 let/const,var 替換成 let 後變數提升就不複存在了。

function test() {  alert(declaredButNotAssigned1); // 報異常  alert(declaredButNotAssigned2); // 報異常  alert(func); // 報異常   let declaredButNotAssigned1;  let declaredButNotAssigned2 = true;  let func = function() {};}test();

這強製程序員養成好的習慣,變數需要“先聲明再使用”,否則報錯。

以下摘自MDN的關於let不在發生變數提升的描述

複製代碼 代碼如下:
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',來判斷是否引入了某lib,比如jQuery

// 判斷jQuery是否引入了if (typeof $ !== 'undefined') {  // do something}...

jQuery沒有引入,$ 沒有聲明,這句也不會報錯而影響到下面的代碼執行,但如果是 let 聲明的就會報錯了。

以上所述就是本文的全部內容了,希望大家能夠喜歡。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.