JavaScript 有哪些资料型别 (data types)? 该怎么辨别一个变数的资料型别?
2023年8月21日
如同绝大多数的程式语言,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 (布林值)
有 true
与 false
两个值的布林值,也是 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
一样可以用+
, *
, -
, **
, 与 %
等运算子,不过要注意不可以拿BigInt
跟number
型别的值交互使用,这会出现TypeError
。
Undefined
undefined
是一个型别,它本身也是一个值。假如某个变数还没被宣告,我们就先使用,在 JavaScript 会出现索引错误 ReferenceError
(如果是用 let
与 const
来宣告该变数)。但如果是宣告了,但没有赋予某个值,这时因为对 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 val | Result |
---|---|
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]