JavaScript 有哪些资料型别 (data types)? 该怎么辨别一个变数的资料型别?

2023年8月21日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

如同绝大多数的程式语言,JavaScript 有其内建的资料型别。其中又有分原生值 (primitive values) 以及物件 (objects)。你知道在 JavaScript 当中有哪些是原生值? 哪些是物件? 又可以透过什么样的方法来辨别某个变数是什么型别呢? 让我们一起来看看这题面试常出现的基础题吧!

JavaScript 的原生值 (primitive values)

截至目前,JavaScript 的资料型别中,有七个原生值。这七个原生值以外的,全都是属于物件。

原生值是不可变的 (immutable),意思是我们不能改变那个值本身。举例来说字串(string) 是其中一个 JavaScript 原生值,我们不能去改变'Hi' 这一个字串(但在其他程式语言,字串有可能是可变的,例如在 C 就是可变的)。我们仅可以把某个变数,赋予另一个字串,例如:

let greeting = "Hi";
greeting = "Hello"; // 赋予另一个值,但上面的 'Hi' 本身没变动

JavaScript 的型别中的七个原生值包含

String (字串)

字串是最常见的原生值之一。如前面提到,在 JavaScript 当中字串本身是不可变的。当我们用 substring() 来撷取字串,或用 concat() 来把两个字串合为一,这些都是会回传另一个字串,而非改变原本的字串。

Boolean (布林值)

truefalse 两个值的布林值,也是 JavaScript 的原生值。

Number

JavaScript 与一些语言不同,没有分整数与浮点数,而是都用 number 这个原生值。不论整数或浮点数,都是 number 这个型别。在 JavaScript 当中,+Infinity-Infinity, 与   NaN 都是 number 这个型别,所以我们用 typeof 来检查的话,会得到 number

console.log(typeof NaN); // number

number 在 JavaScript 是双精度浮点数,所以精确度是介于 -(2^53 − 1)2^53 − 1 之间。在这个范围之外,就会有精准度的问题,这时候要用另一个原生值 BigInt

BigInt

上面提到在 JavaScript 的整数与浮点数,都是用 number 这个型别,这其实只说了一半。因为 JavaScript 的 number 精准度有其限制,虽然多数情况很够用 (2^53 - 1 会是 9007199254740991,我们很少用到比这大的数)。但有些时候会需要更往下的精准度。这时就可以用 BigInt 数值的型别。

BigInt 可以让我们任意选择其精准度,就可以避免一些 number 会遇到的问题。它跟number 一样可以用+*-**, 与  % 等运算子,不过要注意不可以拿BigIntnumber 型别的值交互使用,这会出现TypeError

Undefined

undefined 是一个型别,它本身也是一个值。假如某个变数还没被宣告,我们就先使用,在 JavaScript 会出现索引错误 ReferenceError (如果是用 letconst 来宣告该变数)。但如果是宣告了,但没有赋予某个值,这时因为对 JavaScript 来说,它不知道该变数的值是什么,所以会印出 undefined

// 还没宣告就使用,会有 `ReferenceError`
console.log(greeting); // Uncaught ReferenceError: greeting is not defined
let greeting;
// 宣告了但还没赋值,会是 `undefined`
let greeting;
console.log(greeting); // undefined

Null

null 是很容易跟 undefined 搞混的原生值。 undefined 是因为某变数还没有赋值,所以对 JavaScript 来说,它不知道该变数的值是什么,所以要读取该变数时,会是 undefined。不过 null 则是我们赋予某个变数 null 这一个值。

Symbol

最后一个 JavaScript 原生值是 Symbol,它是一个独特 (unique) 值,多半会搭配物件一起使用,作为物件的键 (key)。

const sym = Symbol("ExplainThis");
const obj = { [sym]: "Interview Preps for Software Engineers" };
obj[sym]; // Interview Preps for Software Engineers

JavaScript 的物件 (objects)

除了上述的七个原生值以外的存在,在 JavaScript 当中都是物件。在 JavaScript 有一个梗是

Objects, Arrays, Functions, Objects 当中,Objects 好像被重复提了两次。喔不,其实是四次。

会说 Objects 被提了四次说因为在 JavaScript 当中,Array (数组) 与 Function (函式),都是物件。

如何辨别一个变数的资料型别?

要辨别一个变数的资料型别,最常见的方式是透过 typeof 这个方法。举例来说 typeof 判断字串。

let greeting = "hi";
console.log(typeof greeting); // 'string'

不过在 JavaScript 当中,有几个小例外,其中一个是 null 。如果用 typeof 判断 null 的资料型别,会得到 object

console.log(typeof null); // object

这是一个 JavaScript 的历史遗迹,但因为要改掉这个 bug 的成本太高,所以到目前为止还是有这个错误。

不论如何, null 的资料型别应该是 null 而不是 object。

另一点要注意的是,typeof 判断数组时,会回传 object; 但判断函式时,会回传 function

console.log(typeof []); // object
console.log(typeof function () {}); // function

补充 typeof 结果的表格,来源参考 ECMAScript® 2015 Language Specification

Type of valResult
Undefined"undefined"
Null"object"
Boolean"boolean"
Number"number"
String"string"
Object (native and does not implement [[Call]])"object"
Object (native or host and does implement [[Call]])"function"
Object (host and does not implement [[Call]])Implementation-defined except may not be "undefined", "boolean", "number", or "string".

我们该如何辨别某个变数是物件,还是数组呢?

Array.isArray() 是可以协助我们的方法。如果是数组,会回传 true;但若是一般物件,则会回传 false。举例来说:

Array.isArray([1, 2, 3]); // true
Array.isArray({ foo: 123 }); // false

我们也可以透过 Object.prototype.toString() 的方法帮助我们辨别数组、函式与一般物件。

const arr = [1, 2, 3];
const fn = () => {
  return 123;
};
const obj = { foo: 123 };

console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(fn)); // [object Function]
console.log(Object.prototype.toString.call(obj)); // [object Object]
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們