JavaScript 基本数据类型:数据的基础构建块
打开你的工具箱,里面有各种各样的工具——螺丝刀、扳手、锤子、尺子。每种工具都有特定的用途,用对了工具,工作才能高效完成。JavaScript 的数据类型就像这些工具,不同类型的数据有不同的用途和特性。
数据类型概述
JavaScript 有两大类数据类型:
- 基本数据类型(Primitive Types):简单的、不可变的值
- 引用数据类型(Reference Types):复杂的、可变的对象
本文重点讲解基本数据类型。JavaScript 共有 7 种基本数据类型:
- Number(数字)
- String(字符串)
- Boolean(布尔值)
- Null(空值)
- Undefined(未定义)
- Symbol(符号,ES6)
- BigInt(大整数,ES2020)
// 使用 typeof 运算符检查数据类型
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof 123n); // "bigint"
console.log(typeof null); // "object" (这是个历史遗留bug!)Number 类型——数字的世界
在 JavaScript 中,所有数字都是 Number 类型,不区分整数和浮点数。这就像一个万能计算器,可以处理各种数值运算。
数字的表示方式
// 整数
let age = 25;
let score = 100;
// 浮点数(小数)
let price = 19.99;
let temperature = -15.5;
// 科学记数法
let bigNumber = 1.5e6; // 1500000
let smallNumber = 2.5e-3; // 0.0025
// 不同进制
let decimal = 255; // 十进制
let binary = 0b11111111; // 二进制(前缀 0b)
let octal = 0o377; // 八进制(前缀 0o)
let hex = 0xff; // 十六进制(前缀 0x)
console.log(binary, octal, hex); // 255 255 255(都转换为十进制)特殊数值
JavaScript 的 Number 类型有几个特殊值:
// Infinity:无穷大
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity > 1000000); // true
// NaN:Not a Number(不是数字)
console.log(0 / 0); // NaN
console.log("hello" * 2); // NaN
console.log(Math.sqrt(-1)); // NaN
// 检查 NaN
console.log(isNaN(NaN)); // true
console.log(isNaN("hello")); // true
console.log(Number.isNaN(NaN)); // true(更严格)
console.log(Number.isNaN("hello")); // false(更严格)
// NaN 的特殊性:它不等于任何值,包括自己!
console.log(NaN === NaN); // false
console.log(NaN == NaN); // false数字的精度问题
由于计算机采用二进制存储,浮点数运算可能出现精度问题。这是所有编程语言的通病,不是 JavaScript 独有的。
// 精度问题示例
console.log(0.1 + 0.2); // 0.30000000000000004(不是 0.3!)
console.log(0.1 + 0.2 === 0.3); // false
// 解决方案 1:使用 toFixed()
let result = (0.1 + 0.2).toFixed(2);
console.log(result); // "0.30"(注意:返回字符串)
console.log(+result); // 0.3(转回数字)
// 解决方案 2:先转换为整数运算
let sum = (0.1 * 10 + 0.2 * 10) / 10;
console.log(sum); // 0.3
// 解决方案 3:使用 Number.EPSILON 进行比较
function almostEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(almostEqual(0.1 + 0.2, 0.3)); // true数字的范围
// 最大安全整数和最小安全整数
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
// 检查是否是安全整数
console.log(Number.isSafeInteger(9007199254740991)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
// 最大值和最小值(包含浮点数)
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324String 类型——文本的艺术
字符串是用来表示文本数据的,就像写在纸上的文字。在 JavaScript 中,字符串可以用单引号、双引号或反引号包围。
字符串的创建
// 单引号
let name1 = "Alice";
// 双引号
let name2 = "Bob";
// 反引号(模板字符串,ES6)
let name3 = `Charlie`;
// 三种方式完全等价(对于简单字符串)
console.log(name1, name2, name3); // Alice Bob Charlie字符串的特殊字符
// 转义字符
let path = "C:\\Users\\Desktop\\file.txt"; // 反斜杠需要转义
let quote = 'He said, "Hello!"'; // 引号需要转义
let single = "It's a nice day."; // 单引号中的单引号需要转义
// 常见转义字符
let newline = "First line\nSecond line"; // \n 换行
let tab = "Column1\tColumn2"; // \t 制表符
let backspace = "Hello\b"; // \b 退格
let unicode = "\u4F60\u597D"; // \uXXXX Unicode 字符
console.log(unicode); // "你好"
console.log(newline);
// First line
// Second line模板字符串(Template Literals)
模板字符串是 ES6 引入的强大功能,用反引号包围,可以方便地嵌入变量和表达式。
let userName = "Emma";
let age = 28;
// 传统拼接方式(繁琐)
let greeting1 = "Hello, " + userName + "! You are " + age + " years old.";
// 模板字符串(简洁)
let greeting2 = `Hello, ${userName}! You are ${age} years old.`;
console.log(greeting1);
console.log(greeting2);
// 两者输出相同:Hello, Emma! You are 28 years old.
// 可以嵌入表达式
let price = 100;
let quantity = 3;
let message = `Total: $${price * quantity}`;
console.log(message); // Total: $300
// 可以调用函数
function getGreeting() {
return "Good morning";
}
let welcome = `${getGreeting()}, ${userName}!`;
console.log(welcome); // Good morning, Emma!
// 多行字符串
let multiline = `
This is a
multi-line
string.
`;
console.log(multiline);字符串的属性和方法
let text = "JavaScript";
// 长度属性
console.log(text.length); // 10
// 访问字符
console.log(text[0]); // "J"
console.log(text.charAt(0)); // "J"
console.log(text.charAt(4)); // "S"
// 字符串是不可变的
text[0] = "j"; // 无效!字符串不能被修改
console.log(text); // 仍然是 "JavaScript"
// 要改变字符串,只能创建新字符串
let newText = "j" + text.slice(1);
console.log(newText); // "javaScript"Boolean 类型——真与假的世界
布尔类型只有两个值:true 和 false。它就像开关,只有"开"和"关"两种状态。
let isActive = true;
let hasPermission = false;
console.log(typeof isActive); // "boolean"
// 比较运算符返回布尔值
console.log(5 > 3); // true
console.log(10 === 10); // true
console.log(7 < 2); // false
// 逻辑运算符
let a = true;
let b = false;
console.log(a && b); // false(与运算)
console.log(a || b); // true(或运算)
console.log(!a); // false(非运算)真值和假值(Truthy & Falsy)
在 JavaScript 中,所有值都可以转换为布尔值。某些值在布尔上下文中被视为 false,称为假值(Falsy);其他值被视为 true,称为真值(Truthy)。
// JavaScript 中只有 6 个假值
Boolean(false); // false
Boolean(0); // false
Boolean(""); // false(空字符串)
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false
// 所有其他值都是真值
Boolean(true); // true
Boolean(1); // true
Boolean("hello"); // true
Boolean(" "); // true(空格也是字符)
Boolean([]); // true(空数组)
Boolean({}); // true(空对象)
Boolean(function () {}); // true
// 实际应用
let username = "";
if (username) {
console.log("Welcome, " + username);
} else {
console.log("Please log in"); // 这个会执行,因为 "" 是假值
}Null 类型——刻意的空
null 表示"故意设置为空"的值,就像一个空盒子,你知道它是空的,是特意放在那里的空位置。
let result = null; // 明确表示"没有值"
console.log(typeof null); // "object"(这是 JavaScript 的历史 bug!)
// 实际使用场景
let selectedUser = null; // 当前没有选中用户
function findUser(id) {
// 查找用户...
if (找不到) {
return null; // 明确返回"没找到"
}
return user;
}
// 检查 null
if (selectedUser === null) {
console.log("No user selected");
}Undefined 类型——未定义的状态
undefined 表示"还没有赋值"的状态,是变量声明了但还没有初始化时的默认值。
let uninitializedVar;
console.log(uninitializedVar); // undefined
console.log(typeof uninitializedVar); // "undefined"
// 不同场景的 undefined
// 1. 声明但未赋值
let x;
console.log(x); // undefined
// 2. 访问不存在的对象属性
let person = { name: "Oliver" };
console.log(person.age); // undefined
// 3. 函数没有返回值
function noReturn() {
// 没有 return 语句
}
console.log(noReturn()); // undefined
// 4. 函数参数未提供
function greet(name) {
console.log(name);
}
greet(); // undefinedNull vs Undefined
这两者很容易混淆,但它们有明确的区别:
// undefined:变量声明了但未赋值
let a;
console.log(a); // undefined
// null:明确赋值为"空"
let b = null;
console.log(b); // null
// 类型检查
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(历史bug)
// 比较
console.log(undefined == null); // true(值相等)
console.log(undefined === null); // false(类型不同)
// 实际应用原则
let config; // undefined:未初始化
let userProfile = null; // null:故意设为空,表示"还没有用户"Symbol 类型——独一无二的标识
Symbol 是 ES6 引入的新类型,用于创建独一无二的标识符。每个 Symbol 都是唯一的,即使描述相同。
// 创建 Symbol
let sym1 = Symbol();
let sym2 = Symbol();
console.log(sym1 === sym2); // false(每个都是唯一的)
// 带描述的 Symbol
let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false(描述相同,但仍是不同的 Symbol)
console.log(id1.description); // "id"
// 使用场景:对象的唯一属性名
let user = {
name: "Sophia",
age: 30,
};
let uniqueID = Symbol("id");
user[uniqueID] = 12345;
console.log(user[uniqueID]); // 12345
console.log(user); // { name: "Sophia", age: 30, Symbol(id): 12345 }
// Symbol 属性不会出现在常规遍历中
for (let key in user) {
console.log(key); // 只输出 "name" 和 "age"
}
// 需要专门的方法访问
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]全局 Symbol 注册表
// Symbol.for() 创建或获取全局 Symbol
let globalSym1 = Symbol.for("app.id");
let globalSym2 = Symbol.for("app.id");
console.log(globalSym1 === globalSym2); // true(同一个 Symbol)
// Symbol.keyFor() 获取全局 Symbol 的键
console.log(Symbol.keyFor(globalSym1)); // "app.id"
// 普通 Symbol 不在全局注册表中
let localSym = Symbol("local");
console.log(Symbol.keyFor(localSym)); // undefinedBigInt 类型——超大整数
BigInt 是 ES2020 引入的类型,用于表示任意精度的整数,突破了 Number 类型的整数限制。
// 创建 BigInt:数字后加 n
let bigInt1 = 123456789012345678901234567890n;
let bigInt2 = BigInt("987654321098765432109876543210");
console.log(typeof bigInt1); // "bigint"
// Number 类型的限制
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(9007199254740992); // 9007199254740992(已不精确)
console.log(9007199254740993); // 9007199254740992(错误!)
// BigInt 没有限制
console.log(9007199254740993n); // 9007199254740993n(精确)
// 运算
let big1 = 100n;
let big2 = 200n;
console.log(big1 + big2); // 300n
console.log(big1 * big2); // 20000n
console.log(big2 / big1); // 2n(除法结果向下取整)
// BigInt 和 Number 不能混合运算
let num = 10;
let big = 20n;
console.log(big + num); // TypeError: Cannot mix BigInt and other types
// 需要显式转换
console.log(big + BigInt(num)); // 30n
console.log(Number(big) + num); // 30BigInt 的限制
// 不能使用 Math 对象的方法
let big = 25n;
console.log(Math.sqrt(big)); // TypeError
// 不能与 Number 比较(用 == 可以,用 === 不行)
console.log(10n == 10); // true
console.log(10n === 10); // false
// 不能用于 JSON.stringify
let data = { value: 100n };
console.log(JSON.stringify(data)); // TypeError: Do not know how to serialize a BigInt类型检查方法
typeof 运算符
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof 123n); // "bigint"
console.log(typeof null); // "object"(bug!)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function () {}); // "function"更准确的类型检查
// 检查 null
let value = null;
console.log(value === null); // true
// 检查数组
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
// Object.prototype.toString.call()
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(getType(123)); // "Number"
console.log(getType("hello")); // "String"
console.log(getType(true)); // "Boolean"
console.log(getType(null)); // "Null"
console.log(getType(undefined)); // "Undefined"
console.log(getType([])); // "Array"
console.log(getType({})); // "Object"总结
基本数据类型是 JavaScript 编程的基础,理解它们的特性对于编写正确的代码至关重要。
本节要点回顾:
- JavaScript 有 7 种基本数据类型:Number、String、Boolean、Null、Undefined、Symbol、BigInt
- Number:所有数字类型,注意精度问题和特殊值(NaN、Infinity)
- String:文本数据,推荐使用模板字符串
- Boolean:true/false,理解真值和假值的概念
- Null:故意设置的空值
- Undefined:未定义或未初始化的状态
- Symbol:创建唯一标识符(ES6)
- BigInt:任意精度的整数(ES2020)
- 使用
typeof检查类型,但要注意typeof null的特殊情况 - 基本类型的值是不可变的(immutable)