首頁 > web前端 > js教程 > JavaScript中標識符提升問題_javascript技巧

JavaScript中標識符提升問題_javascript技巧

WBOY
發布: 2016-05-16 15:55:58
原創
1316 人瀏覽過

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); // &#63;
}
fn();
登入後複製

題2:

// 写出以下代码的运行结果
var a = 1;
function fn() {
  a = 2;
  return;
  function a() {}
}
fn();
alert(a); // &#63;

登入後複製

但這一切隨著 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, incause the vor. 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 宣告的就會報錯了。

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

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板