面試官問「JS 的型別」時,到底想聽到什麼?

面試官問「JS 的型別」時,到底想聽到什麼?

這不是一篇基礎教學,而是一次思維升級。如果你只停留在「知道有哪些型別」的層面,那你和面試官之間還差一個 V8。


引子:一個最常見的面試場景

面試官問:「JavaScript 有哪些資料型別?」

初級回答(大部分人):

「有 string、number、boolean、null、undefined、object……還有 symbol?」

面試官(內心):背八股文呢?

進階回答(你):

「JS 的型別可以分為兩大類——基本型別和參照型別。這種分類不是拍腦袋定的,而是由 V8 引擎的記憶體管理機制決定的。基本型別體積小,直接存在堆疊裡;參照型別體積不定,存在堆積裡,堆疊裡只存 8 位元組的位址指標。這樣做的好處是——」

面試官(眼睛一亮):這人懂底層。

差距在哪裡? 前者只是列舉,後者是解釋為什麼


一、先搞定分類——別讓 null 坑了你

1.1 兩張大表記清楚

基本型別(7 種)——值直接存堆疊裡

類型 例子 常見坑 string 'hello'number 42 NaN 也是 number 型別 boolean true !! 是布林轉換的快捷方式 undefined let a 宣告未賦值 null null ⚠️ typeof null'object' bigint 10n ES2020 才加入 Symbol Symbol('id') 每次呼叫都是唯一值

參照型別(常見 4 種)——值存堆積裡,堆疊存位址

類型 例子 說明 Object { name: 'Alice' } 一切參照型別的祖宗 Array [1, 2, 3] typeof []'object' Function function() {} JS 中函式也是物件 Date new Date() ⚠️ Date() 不是 Date 型別,是字串!

1.2 終極記憶法

七個基本用一個口訣記住:

「宋(string)數(number)不(boolean)定(undefined)空(null)大(bigint)象(Symbol)」

七種基本型別,一個不少。

參照型別只記一句話:

「除了以上七種,其他全是物件」


二、核心差異——賦值行為見真章

自己跑一下這三行程式碼,你就懂了:

javascript 体验AI代码助手 代码解读复制代码// 場景 A:基本型別賦值
let a = 10;
let b = a;
b = 20;
console.log(a); // 猜猜是 10 還是 20?
javascript 体验AI代码助手 代码解读复制代码// 場景 B:參照型別賦值
let objA = { count: 10 };
let objB = objA;
objB.count = 20;
console.log(objA.count); // 猜猜是 10 還是 20?

答案:

  • 場景 A:10 ✅ — 基本型別賦值是複製值,a 和 b 沒關係了
  • 場景 B:20 ⚠️ — 參照型別賦值是複製位址,objA 和 objB 指向同一個物件

記法:基本型別像影印件——改一個不影響另一個;參照型別像捷徑——不管從哪個入口進去,改的都是同一個檔案。


三、為什麼 JS 要這麼設計?——V8 的智慧

這是很多人知道「是什麼」卻說不清「為什麼」的關鍵。

3.1 來,在腦子裡畫張圖

ini 体验AI代码助手 代码解读复制代码執行這段程式碼時,V8 在記憶體裡做了什麼:

let name = 'GGBond';
let age = 20;
let girlFriend = {
  name: 'feifei',
  hobbies: ['coding', 'reading']
};

畫出來是這樣的:

css 体验AI代码助手 代码解读复制代码┌────────── 堆疊(Call Stack)──────────┐
│                                      │
│  name: 'GGBond'      ← 字串直接存     │
│  age: 20            ← 數字直接存      │
│  girlFriend: ● ————————┐              │
│                     │                │
└─────────────────────│────────────────┘
                      │  參照位址(8 位元組)
                      ▼
┌────────── 堆積(Heap)────────────────┐
│                                      │
│  { name: 'feifei',                  │
│    hobbies: ● ————→ ['coding',       │
│  }                        'reading'] │
│                                      │
└──────────────────────────────────────┘

3.2 為什麼不能反過來?——V8 的真正考量

❌ 錯誤方案:所有資料都放堆疊裡

如果 girlFriend 這個大物件也放進堆疊:

  • 堆疊的大小是固定的(通常 1-2MB)
  • 一個大物件可能就占幾百 KB
  • 再來幾個物件 → 爆堆疊(Stack Overflow)

❌ 錯誤方案:所有資料都放堆積裡

如果連 age = 20 也要去堆積裡分配:

  • 堆積的存取速度比堆疊慢 10 倍以上
  • 一個數字才 8 位元組,為了它去堆積裡開闢空間,得不償失

✅ V8 的選擇:混合儲存

 体验AI代码助手 代码解读复制代码基本型別(小、輕) → 堆疊    — 快就完了
參照型別(大、不定)→ 堆積    — 堆疊不會爆
參照位址(8 位元組) → 堆疊    — 查詢時透過位址找資料

一句話總結:堆疊管速度,堆積管容量。V8 用最小代價換來了最大效率。


四、型別檢測——避開常見的坑

4.1 三種檢測方法

typeof —— 適合基本型別(除 null)

javascript 体验AI代码助手 代码解读复制代码typeof 'hello'    // 'string'
typeof 42         // 'number'
typeof true       // 'boolean'
typeof undefined  // 'undefined'
typeof Symbol()   // 'symbol'
typeof 10n        // 'bigint'

typeof null       // 'object'  ← 歷史遺留 bug
typeof []         // 'object'  ← 陣列也是 object
typeof {}         // 'object'

規律:除了 null,基本型別的 typeof 都能對上。

instanceof —— 適合參照型別

javascript 体验AI代码助手 代码解读复制代码[] instanceof Array        // true
{} instanceof Object       // true
new Date() instanceof Date // true

'hello' instanceof String  // false ❌ 基本型別不行

注意:[] instanceof Object 也是 true!因為原型鏈上能找到 Object。

Object.prototype.toString —— 萬能方法

javascript 体验AI代码助手 代码解读复制代码function getType(v) {
  return Object.prototype.toString.call(v).slice(8, -1);
}

getType('hello')    // 'String'
getType(null)       // 'Null'
getType([])         // 'Array'
getType(new Date()) // 'Date'
getType(new Map())  // 'Map'

4.2 面試常問:手寫一個型別判斷函式

javascript 体验AI代码助手 代码解读复制代码function typeOf(value) {
  // null 單獨處理
  if (value === null) return 'null';

  // 基本型別用 typeof
  const base = typeof value;
  if (base !== 'object' && base !== 'function') return base;

  // 參照型別用 toString
  const tag = Object.prototype.toString.call(value);
  return tag.slice(8, -1).toLowerCase();
}

// 測試
typeOf('hello')   // 'string'
typeOf(null)      // 'null'     ✅ 修復了 typeof null 的 bug
typeOf([])        // 'array'
typeOf(new Date())// 'date'
typeOf(new Map()) // 'map'

五、V8 執行全過程——把知識串起來

5.1 完整流程

javascript 体验AI代码助手 代码解读复制代码let num = 10;
let str = 'hello';
let obj = { key: 'value' };

function add(x, y) {
  return x + y;
}

let result = add(num, 20);

V8 的執行步驟:

less 体验AI代码助手 代码解读复制代码Step 1:建立呼叫堆疊(Call Stack)
Step 2:建立全域執行環境,壓入堆疊底部
Step 3:執行宣告(建立階段)
   ├── num → 堆疊中存 10
   ├── str → 堆疊中存 'hello'
   ├── obj → 堆積中建立 {key:'value'},堆疊存位址 @001
   ├── add → 堆積中存函式體,堆疊存位址 @002
   └── result → 堆疊中存 undefined
Step 4:執行 add(num, 20)
   ├── 建立函式執行環境,入堆疊
   ├── x=10, y=20 存入堆疊中(函式的堆疊)
   ├── 執行 x + y → 回傳 30
   └── 函式執行環境出堆疊
Step 5:result = 30

5.2 這段程式碼會爆堆疊嗎?

javascript 体验AI代码助手 代码解读复制代码function infinite() {
  return infinite();
}
infinite();

會。 每呼叫一次就建立一個執行環境入堆疊,堆疊是有限的,最終:

scss 体验AI代码助手 代码解读复制代码┌───────── 呼叫堆疊 ─────────┐
│ infinite()  // 第10000次    │
│ infinite()  // 第9999次     │
│ ...                         │
│ infinite()  // 第1次        │
│ 全域執行環境                 │
└──────────────────────────┘
RangeError: Maximum call stack size exceeded

這就是「爆堆疊」——參照型別放堆積裡而不是堆疊裡,正是為了防止這種溢位。


寫在最後

這篇文章沒有講什麼高深的東西,而是用「為什麼」把你知道的碎片知識串了起來

JS 型別的核心其實就三句話:

  1. 基本型別存值(堆疊),參照型別存位址(堆疊→堆積)
  2. 這樣設計是為了平衡速度(堆疊)和容量(堆積)
  3. typeof 看基本,toString 看全部

能說出這三句,面試官就知道你不只是學過,還思考過


覺得有用的話按讚 👍 收藏 ⭐,讓更多人看到。
你的面試路上還遇過什麼離譜的 JS 型別題?留言區告訴我。


原文出處:https://juejin.cn/post/7639998881226473512


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝12   💬4   ❤️1
464
🥈
alicec
📝1   ❤️2
87
#4
我愛JS
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登