JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。
一、基本数据类型(原始类型)
1. String(字符串)表示文本数据,用单引号 '' 或双引号 "" 包裹。支持转义字符(如 \n 换行)和模板字符串(ES6)。
2. Number(数字)包含整数、浮点数及特殊值(Infinity、-Infinity、NaN)。JavaScript不区分整型和浮点型,均以64位浮点数存储。
3. Boolean(布尔值)仅有两个值:true 和 false,常用于条件判断。
4. Null表示“空值”,通常用于显式清空变量引用。typeof null 返回 "object"(历史遗留问题)。
5. Undefined表示变量已声明但未赋值,或对象属性不存在时的默认值。
6. Symbol(符号,ES6新增)唯一且不可变的值,常用作对象属性的唯一标识符。
7. BigInt(大整数,ES2020新增)用于表示超出 Number 精度范围的大整数,后缀加 n(如 123n)。
二、引用数据类型(对象类型)
1. Object(对象)键值对的集合,可包含任意类型数据(包括其他对象)。例如:
let person = { name: "John", age: 30 };
2. Array(数组)有序集合,元素可为任意类型。通过索引访问,支持动态长度:
let arr = [1, "two", true];
3. Function(函数)可执行代码块,本质是“可调用对象”。例如:
let arr = [1, "two", true];
4. 其他内置对象包括 Date(日期)、RegExp(正则表达式)、Map/Set(ES6新增数据结构)等。
三、类型特性与操作
1. 动态类型JavaScript是弱类型语言,变量类型可动态改变:
let a = 10; // Number
a = "text"; // 变为 String
2. 类型检测
• typeof:返回类型字符串(如 typeof "text" → "string",但 typeof null → "object")。
• instanceof:检测对象是否为某构造函数的实例(如 arr instanceof Array → true)。
• Array.isArray():专用于检测数组。
3. 类型转换
• 隐式转换:如 5 + "10" → "510"(数字转字符串)。
• 显式转换:使用 Number()、String()、Boolean() 等函数。
四、注意事项
• 引用类型与内存管理:对象类型变量存储的是内存地址,复制时需注意浅拷贝与深拷贝的区别。
• null vs undefined:null 表示空值(需显式赋值),undefined 表示未初始化。
• Symbol与唯一性:Symbol('key') !== Symbol('key'),适用于避免属性名冲突。
Symbol 和 BigInt
其中Symbol 和 BigInt 是 ES6+(ECMAScript 2015+)中新增的数据类型:
Symbol 可以理解为一个独特的标识符。想象一下,你有一把独一无二的钥匙,这把钥匙就是 Symbol。它的主要用途是避免在使用对象属性时发生意外的名字冲突。比如,如果你和别人合作开发一个大型项目,你们都想给一个对象添加一个叫"id"的属性,使用 Symbol 可以确保你们的"id"不会互相覆盖。
BigInt 是专门用来处理特别大的整数的。普通的 Number 类型在JavaScript中有一个最大安全整数(9007199254740991),超过这个数字可能会出现计算错误。而 BigInt 可以安全地表示和计算任意大的整数,就像是给了数字一个无限的跑道。比如,当你需要精确计算天文数字或者处理非常大的金融数据时,BigInt 就非常有用。
这两种数据类型的加入,使得 JavaScript 能够更好地处理独特标识和超大整数,增强了语言的功能性和适用范围。
简单类型和复杂类型
JavaScript 的数据类型可以分为两大类:简单类型和复杂类型。
简单类型(也叫原始类型):
这些类型就像是一个个小盒子,每个盒子里直接装着一个值。
包括:Undefined、Null、Boolean、Number、String、Symbol 和 BigInt。
它们存储在计算机的"栈"内存中,就像一摞盘子,取用方便快捷。
复杂类型(也叫引用类型):
这些类型更像是大箱子,里面可以装很多东西。
主要是 Object 类型,包括普通对象、数组和函数。
它们存储在"堆"内存中,就像一个大仓库,可以存放更多、更复杂的数据。
简单来说,简单类型就是单纯的数据,复杂类型则可以包含更多信息和功能。
两种类型的区别在于存储位置的不同:
栈内存:原始数据类型就像是小纸条,上面写着简单的信息(如数字或文字)。这些小纸条直接放在一个叫"栈"的抽屉里。这个抽屉很小,但是拿东西特别快,所以经常用到的小纸条就放在这里。
堆内存:引用数据类型则像是大箱子,里面可能装着很多东西(如各种衣物)。这些大箱子放在一个叫"堆"的大仓库里。因为箱子太大了,不能直接放在小抽屉里,所以我们在小抽屉里放了一张写有箱子位置的便利贴。当我们需要箱子里的东西时,先在抽屉里找到便利贴,然后按照便利贴上的位置信息去仓库里找到对应的箱子。
数据类型检测
typeof: 7种基础数据类型中除了 null 返回的是 object,其他都能准确返回(包括 Symbol 返回 symbol,BigInt 返回 bigint),复杂数据类型中 Function 类型的数据返回 function,其他都返回 object;
console.log(typeof 42); // 输出: "number"
console.log(typeof "Hello"); // 输出: "string"
console.log(typeof true); // 输出: "boolean"
console.log(typeof Symbol()); // 输出: "symbol"
console.log(typeof 42n); // 输出: "bigint"
console.log(typeof null); // 输出: "object"
console.log(typeof {}); // 输出: "object"
console.log(typeof []); // 输出: "object"
console.log(typeof function(){}); // 输出: "function"
instanceof: 复杂数据类型如Array等都准确返回相应的boolean值,对于基本数据类型则是返回 false (只有是通过new运算符来进行初始化,然后通过instanceof来判断是否是某个类的实例,才会返回true,比如"var k = new Number(11); console.log(k instanceof Number)",其返回true);
console.log([] instanceof Array); // 输出: true
console.log({} instanceof Object); // 输出: true
console.log(new Date() instanceof Date); // 输出: true
console.log(42 instanceof Number); // 输出: false
console.log(new Number(42) instanceof Number); // 输出: true
使用constructor检测:上面的instanceof对于直接声明如:"var a = 1;" 不能进行判断,我们可以通过使用constructor来实现判断,如 "a.constructor==Number" (其返回true,不过对于"1.constructor==Number"这类直接用数值来访问 constructor 的情况是会报错的),但对于null则仍然无法判断 ,而且会报错,比如"var k = null; console.log(k.constructor==Object)";
console.log((42).constructor === Number); // 输出: true
console.log("Hello".constructor === String); // 输出: true
console.log([].constructor === Array); // 输出: true
console.log(({}).constructor === Object); // 输出: true
// console.log(null.constructor === Object); // 这行会报错
使用Object.prototype.toString.call使用:这个方法可以获取所有的类型(包括null型),不过其返回的是类似"object Array"的形式的字符串。
console.log(Object.prototype.toString.call(42)); // 输出: "[object Number]"
console.log(Object.prototype.toString.call("Hello")); // 输出: "[object String]"
console.log(Object.prototype.toString.call(true)); // 输出: "[object Boolean]"
console.log(Object.prototype.toString.call(null)); // 输出: "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // 输出: "[object Undefined]"
console.log(Object.prototype.toString.call([])); // 输出: "[object Array]"
console.log(Object.prototype.toString.call({})); // 输出: "[object Object]"
console.log(Object.prototype.toString.call(function(){})); // 输出: "[object Function]"
注意事项
null的类型检测:
使用typeof null会返回"object",这是 JavaScript 的一个历史遗留 bug。
要准确检测null,可以使用严格相等:value === null
原始值包装对象:
JavaScript 会自动为原始值创建包装对象,这就是为什么我们可以在原始值上调用方法。
例如:"hello".toUpperCase()实际上 JavaScript 会临时创建一个 String 对象。
Symbol 的特殊性:
Symbol 值是唯一的,即使描述相同,两个 Symbol 也不相等。
例如:Symbol('foo') !== Symbol('foo')
BigInt 的使用:
BigInt 数字后面要加n,例如:const bigInt = 1234567890123456789012345678901234567890n;
BigInt 不能与普通数字进行混合运算。
类型转换:
JavaScript 中的类型转换可能会导致意外结果,例如:
console.log([] + []); // 输出空字符串 ""
console.log([] + {}); // 输出 "[object Object]"
console.log({} + []); // 输出 0 (在某些环境下)