7個簡單但容易忽視的 JavaScript 問題 - 閉包、變量提高、浮點數計算...

這篇文章,我將分享7個簡單可是又容易犯錯的 JS 問題。或許日常開發中咱們也會忽視這幾個問題。數組

意外聲明的全局變量

Question

判斷下面代碼中 typeof atypeof b 的值瀏覽器

function foo() {
    let a = b = 0;
    a++;
    return a;
}

foo();
console.log(typeof a); // => ???
console.log(typeof b); // => ???
複製代碼

Answer

讓咱們仔細看一下第2行:let a = b =0。該語句確實聲明瞭局部變量a。可是,咱們也悄悄地聲明瞭全局變量b。bash

在上面的代碼中,沒有在 foo() 範圍或全局範圍中聲明任何變量b。所以JavaScript將 b = 0 表達式解釋爲 window.b = 0閉包

下面幾種不合理地寫法,會聲明全局變量函數

# 1. i 被聲明爲全局變量
function foo(count) {
    for(i=0; i<count; ++i) {

    }
}

# 2. i 被聲明全局變量
function foo() {
    i = 0;
}

# 3. b 被聲明爲全局變量
function foo() {
    let a = b = 0;
    // 咱們能夠寫成 let a=0, b=0;
}
複製代碼

上面問題的代碼,在瀏覽器會被識別爲學習

function foo() {
    let a;
    window.b = 0;
    a = window.b;
    a++;
    return a;
}

foo();
typeof a; // => 'undefined'
typeof window.b; // => 'number'
複製代碼

Array length property

Question

判斷a[0] 的值ui

const a = ['jacket', 't-shirt'];
a.length = 0;

console.log(a[0]); // => undefined
複製代碼

Answer

數組對象的 length 屬性具備特殊的行爲:編碼

減小length屬性的值具備刪除本身的數組元素(其數組索引在新舊長度值之間)的反作用。spa

因爲這種length變化行爲,當JavaScript執行 a.length = 0 時,將刪除數組衣服的全部元素。插件

Eagle eye test

Question

判斷 numbers 數組的值:

const length = 4;
const numbers = [];
for (var i = 0; i < length; i++);{
  numbers.push(i + 1);
}

console.log(numbers); // => ???

#### Answer
複製代碼

相應不少人一開始都會一直認爲結果爲[1,2,3,4],實際上在 for 循環一行中增長了一個分號;,所以for()遍歷null語句4次(不執行任何操做),而忽略實際將項目推入數組的塊:{number.push(i + 1); }

const length = 4;
const numbers = [];
var i;
for (i = 0; i < length; i++) {
  // does nothing
}
{ 
  // a simple block
  numbers.push(i + 1);
}

numbers; // => [5]
複製代碼

Automatic semicolon insertion

Question

arrayFromValue() 返回何值:

function arrayFromValue(item) {
  return
    [items];
}

console.log(arrayFromValue(10)); // => ???
複製代碼

Answer

上面代碼,若是在 vscode 經過格式化插件,確定會有規範代碼,可是若是在一些控制檯或者沒格式化的狀態下寫的代碼,很容易就到 return 就返回了undefined,以下:

function arrayFromValue(item) {
  return;
  [items];
}

arrayFromValue(10); // => undefined
複製代碼

經典問題:閉包

Question

分析代碼將在控制檯打印的結果:

let i;
for (i = 0; i < 3; i++) {
  const log = () => {
    console.log(i);
  }
  setTimeout(log, 100);
}
複製代碼

Answer

在剛開始學習 JS 的時候,都會認爲輸出結果爲0,1,2,實際上,執行此代碼段有兩個階段:

  1. 階段一:
    1. for() 重複3次。在每次迭代過程當中,都會建立一個新的函數log()來捕獲變量i。而後setTimout()計劃執行log()
    2. 當for()循環完成時,i變量的值爲3

log() 是一個捕獲變量i的閉包,該變量在for()循環的外部範圍中定義

  1. 階段二: 第二階段發生在100ms以後
    1. 3個計劃的log()回調由setTimeout()調用。 log()讀取變量i的當前值3,並將其記錄到控制檯3

這也就是爲何最後的輸出結果爲3了,若是須要輸出0,1,2,只須要將 let i 聲明到 for 裏面便可。這時候就會生成塊級的做用域,而後 log 函數就會存儲每次循環中 i 的值。

Floating point math

Question

O(∩_∩)O哈哈~,這個問題已經算是老生常談了,都瞭解 JS 下段代碼會輸出什麼結果,或者不會輸出什麼結果:

0.1 + 0.2 === 0.3 ?
複製代碼

Answer

0.1 + 0.2; // => 0.30000000000000004
複製代碼

因爲 JS 是以二進制方式對浮點數進行編碼,所以像浮點數相加之類的操做會產生舍入偏差。

簡而言之,直接比較浮點數並不精確。

Hoisting

Question

若是在聲明前訪問myVar和myConst,會發生什麼狀況?

myVar;   // => ???
myConst; // => ???

var myVar = 'value';
const myConst = 3.14;
複製代碼

Answer

變量提高和塊級做用域是影響JavaScript變量生命週期的兩個重要概念。

總結

上面幾個問題,可能通常都不會問道,畢竟知識深度比較淺,可是咱們也不能忽視,特別是鷹眼和閉包問題。

😉😇😉晚安,深夜放文~~~~

相關文章
相關標籤/搜索