JavaScript有哪些数据类型?如何判断一个变量的数据类型?
JavaScript 有其内建的数据类型。其中又分为原生值(primitive values)和对象(objects)。
1.JavaScript 的原生值 (primitive values)
截至目前,JavaScript 的资料型别中,有七个原生值。这七个原生值以外的,全都是属于对象。
原生值是不可变的(immutable),意思是我们不能改变那个值本身。比如当我们"修改"原始值时,实际上是让变量重新绑定到一个新的值,而不是在原值上进行修改。
javascript
let greeting = "Hi";
greeting = "Hello"; // 此时虽然打印 greeting 是 Hello,但是 Hi 这个值本身是没变的,只是 greeting 指向了Hello 这个新值
JavaScript 的型别中的七个原生值包含:
1.1 字符串 String
String (字符串)
字串是最常见的原生值之一。如前面提到,在JavaScript 当中字串本身是不可变的。当我们用substring()来撷取字串,或用concat()来把两个字串合为一,这些都是会回传另一个字串,而非改变原本的字串。
1.2 布尔值 Boolean
Boolean (布尔值)
有true与false两个值的布林值,也是JavaScript 的原生值。
1.3 Number
JavaScript 与一些语言不同,没有分整数与浮点数,而是都用number这个原生值。不论整数或浮点数,都是number这个型别。在JavaScript 当中,+Infinity, -Infinity, 与 NaN 都是number这个型别,所以我们用typeof来检查的话,会得到number。
javascript
console.log(typeof NaN); // number
而number在JavaScript 是双精度浮点数,所以精确度是介于-(2^53 − 1)与2^53 − 1之间。在这个范围之外,就会有精准度的问题,这时候要用另一个原生值BigInt。
1.4 BigInt
上面提到在JavaScript 的整数与浮点数,都是用number这个型别,这其实只说了一半。因为JavaScript 的number精准度有其限制,虽然多数情况很够用(2^53 - 1会是9007199254740991,我们很少用到比这大的数)。但有些时候会需要更往下的精准度。这时就可以用BigInt数值的型别。
BigInt可以让我们任意选择其精准度,就可以避免一些number会遇到的问题。它跟number一样可以用+, *, -, **, 与 %等运算子,不过要注意不可以拿BigInt跟number型别的值交互使用,这会出现TypeError。
1.5 Undefined
undefined是一个类型,它本身也是一个值。
-
假如某个变量未声明就是用,会出现索引错误ReferenceError
javascriptconsole.log(a); ReferenceError: a is not defined -
用 let / const 声明了,但在声明前使用
javascriptconsole.log(a); let a = 1; ReferenceError: Cannot access 'a' before initialization -
某个变量声明但是没有赋值
javascriptlet greeting; console.log(greeting); // undefined
1.6 Null
null是很容易跟undefined搞混的原生值。undefined是因为某变数还没有赋值,所以对JavaScript 来说,它不知道该变数的值是什么,所以要读取该变数时,会是undefined。不过 则null是我们赋予某个变数null这一个值。
1.7 Symbol
最后一个JavaScript 原生值是Symbol,它是一个独特(unique) 值,多半会搭配物件一起使用,作为物件的键(key)。
javascript
const sym = Symbol("ExplainYYDS");
const obj = { [sym]: "Interview Preps for Software Engineers" };
obj[sym]; // Interview Preps for Software Engineers
2.JavaScript中的对象(objects)
除了上述的七个原生值以外的存在,在JavaScript 当中都是对象。
JavaScript 圈有一个梗,数组是对象,函数是对象,对象是对象。
3. 如何辨别一个变量的数据类型?
3.1 使用typeof判断变量的数据类型
要辨别一个变数的数据类型,最常见的方式是透过typeof这个方法。举例来说typeof判断字符串。
javascript
let greeting = "hi";
console.log(typeof greeting); // 'string'
typeof 的两个注意点
- typeof 原生值,返回的是该原生值的类型标识字符串,但是 typeof null 结果不是 null,而是object,这个历史遗留的 bug,修复成本太高了
- typeof 数组的结果是 object ,tpyeof 函数的结果是 function
javascript
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof function () {}); // function
补充typeof结果的表格
| 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". |
因为 typeof 无法判断数组和对象,所以需要新的方法去判断某个变量是对象还是数组。
3.2 判断变量是对象还是数组?
Array.isArray()是可以协助我们的方法。如果是数组,会回传true;但若是一般对象,则会回传false。举例来说:
javascript
Array.isArray([1, 2, 3]); // true
Array.isArray({ foo: 123 }); // false
我们也可以透过Object.prototype.toString()的方法帮助我们辨别数组、函数与一般对象。
javascript
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]