JavaScript 数据类型
引言
在编程语言中,数据类型是一个基础且关键的概念。JavaScript作为一门动态类型语言,拥有自己独特的类型系统。理解JavaScript的数据类型不仅能帮助你写出更健壮的代码,还能避免许多常见的错误。
本文将详细介绍JavaScript中的各种数据类型,帮助你打下坚实的基础。
JavaScript 数据类型概览
JavaScript有两大类数据类型:
- 基本数据类型(原始类型):直接存储简单的数据值
- 引用数据类型(对象类型):存储对复杂数据结构的引用
基本数据类型(原始类型)
JavaScript中有7种基本数据类型:
- Number(数字)
- String(字符串)
- Boolean(布尔值)
- Undefined(未定义)
- Null(空值)
- Symbol(符号,ES6新增)
- BigInt(大整数,ES2020新增)
引用数据类型(对象类型)
JavaScript中的对象类型包括:
- Object(对象)
- Array(数组,是特殊的对象)
- Function(函数,是特殊的对象)
- Date(日期对象)
- RegExp(正则表达式对象)
- Map、Set等(ES6新增)
基本数据类型详解
Number(数字)
JavaScript使用IEEE 754标准的64位浮点数表示所有数字。
// 整数
let int = 42;
// 浮点数
let float = 3.14;
// 科学计数法
let scientific = 5e3; // 5000
// 特殊值
let infinity = Infinity;
let negInfinity = -Infinity;
let notANumber = NaN; // Not a Number
console.log(typeof int); // "number"
JavaScript中没有整数类型,所有数字都是浮点数,这也是为什么0.1 + 0.2 !== 0.3
的原因(浮点数精度问题)。
String(字符串)
字符串是由零个或多个字符组成的文本。在JavaScript中,字符串可以用单引号、双引号或反引号(模板字符串)表示。
let singleQuotes = 'Hello';
let doubleQuotes = "World";
let backticks = `${singleQuotes}, ${doubleQuotes}!`; // 模板字符串支持插值
console.log(backticks); // "Hello, World!"
console.log(typeof backticks); // "string"
常用字符串方法
let text = "JavaScript";
console.log(text.length); // 10
console.log(text.toUpperCase()); // "JAVASCRIPT"
console.log(text.substring(0, 4)); // "Java"
console.log(text.indexOf("Script")); // 4
Boolean(布尔值)
布尔类型只有两个值:true
和false
,用于表示逻辑值。
let isActive = true;
let isLoggedIn = false;
console.log(typeof isActive); // "boolean"
以下值在条件语句中会被视为假(falsy):
false
0
''
(空字符串)null
undefined
NaN
其他所有值,包括所有对象,即使是空对象{}
,都被视为真(truthy)。
Undefined
当变量被声明但没有赋值时,它的值是undefined
。函数如果没有返回值,默认也返回undefined
。
let notAssigned;
console.log(notAssigned); // undefined
function noReturn() {
// 没有return语句
}
console.log(noReturn()); // undefined
console.log(typeof notAssigned); // "undefined"
Null
null
表示一个空值或不存在的对象引用。它是一个特殊的值,表示"没有值"或"空"。
let empty = null;
console.log(empty); // null
// 注意:typeof null的结果是"object",这是JavaScript中的一个历史遗留bug
console.log(typeof empty); // "object"
typeof null
返回"object"
是JavaScript的一个著名bug,但由于历史原因无法修复,因为这会破坏现有代码。
Symbol(ES6新增)
Symbol是ES6引入的新原始数据类型,表示唯一的、不可变的值,主要用作对象属性的键。
let id = Symbol("id");
let id2 = Symbol("id");
console.log(id === id2); // false,每个Symbol值都是唯一的
let user = {
name: "John",
[id]: 123 // 使用Symbol作为对象属性
};
console.log(user[id]); // 123
console.log(typeof id); // "symbol"
BigInt(ES2020新增)
BigInt是一种内置对象,可以表示任意精度的整数。
// 创建BigInt的方法:在整数末尾加n或使用BigInt()构造函数
let bigNumber = 1234567890123456789012345678901234567890n;
let anotherBig = BigInt("9007199254740991");
console.log(bigNumber + 1n); // 1234567890123456789012345678901234567891n
console.log(typeof bigNumber); // "bigint"
引用数据类型详解
Object(对象)
对象是JavaScript中最复杂的数据类型,可以存储各种键值对。
let person = {
firstName: "John",
lastName: "Doe",
age: 30,
isEmployee: true,
sayHello: function() {
return `Hello, my name is ${this.firstName} ${this.lastName}`;
}
};
console.log(person.firstName); // "John"
console.log(person["lastName"]); // "Doe"
console.log(person.sayHello()); // "Hello, my name is John Doe"
console.log(typeof person); // "object"
Array(数组)
数组是一种特殊类型的对象,用于存储有序的数据集合。
let fruits = ["Apple", "Banana", "Orange"];
console.log(fruits[0]); // "Apple"
console.log(fruits.length); // 3
// 添加元素
fruits.push("Mango");
console.log(fruits); // ["Apple", "Banana", "Orange", "Mango"]
// 数组方法
console.log(fruits.join(", ")); // "Apple, Banana, Orange, Mango"
let citrus = fruits.slice(1, 3);
console.log(citrus); // ["Banana", "Orange"]
console.log(typeof fruits); // "object"
console.log(Array.isArray(fruits)); // true
Function(函数)
函数在JavaScript中是一种特殊的对象,可以被调用执行。
// 函数声明
function add(a, b) {
return a + b;
}
// 函数表达式
const multiply = function(a, b) {
return a * b;
};
// 箭头函数(ES6)
const subtract = (a, b) => a - b;
console.log(add(5, 3)); // 8
console.log(multiply(5, 3)); // 15
console.log(subtract(5, 3)); // 2
console.log(typeof add); // "function"
类型检测
在JavaScript中,可以使用多种方式检测数据类型:
typeof运算符
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (这是一个bug)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"
instanceof运算符
instanceof
运算符用于检测对象是否属于某个构造函数的实例。
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true (因为数组也是对象)
let date = new Date();
console.log(date instanceof Date); // true
其他检测方法
// 检测数组
console.log(Array.isArray([1, 2, 3])); // true
// 检测NaN
console.log(isNaN(NaN)); // true
// 检测有限数字
console.log(isFinite(42)); // true
console.log(isFinite(Infinity)); // false
类型转换
JavaScript会自动进行类型转换(也称为类型强制)。此外,你也可以显式地进行类型转换。
自动类型转换
console.log("5" + 2); // "52" (数字转为字符串)
console.log("5" - 2); // 3 (字符串转为数字)
console.log(5 + true); // 6 (布尔值转为数字,true变为1)
console.log(5 + false); // 5 (false变为0)
显式类型转换
// 转为数字
console.log(Number("42")); // 42
console.log(parseInt("42px", 10)); // 42
console.log(parseFloat("3.14")); // 3.14
// 转为字符串
console.log(String(42)); // "42"
console.log((42).toString()); // "42"
// 转为布尔值
console.log(Boolean(0)); // false
console.log(Boolean("hello")); // true
console.log(Boolean("")); // false
实际应用案例
案例1:构建用户资料表单验证
function validateUserProfile(profile) {
// 检查必填字段是否存在且类型正确
if (typeof profile.name !== "string" || profile.name.trim() === "") {
return { valid: false, error: "姓名必须是非空字符串" };
}
if (typeof profile.age !== "number" || isNaN(profile.age)) {
return { valid: false, error: "年龄必须是数字" };
}
if (typeof profile.email !== "string" || !profile.email.includes("@")) {
return { valid: false, error: "邮箱格式不正确" };
}
if (!Array.isArray(profile.interests) || profile.interests.length === 0) {
return { valid: false, error: "兴趣爱好必须是非空数组" };
}
return { valid: true };
}
// 测试
const profile1 = {
name: "Alice",
age: 28,
email: "alice@example.com",
interests: ["coding", "hiking"]
};
const profile2 = {
name: "",
age: "twenty-eight", // 错误的数据类型
email: "alice-example.com", // 缺少@
interests: []
};
console.log(validateUserProfile(profile1)); // { valid: true }
console.log(validateUserProfile(profile2)); // { valid: false, error: "姓名必须是非空字符串" }
案例2:购物车金额计算
function calculateCartTotal(items) {
// 确保items是数组
if (!Array.isArray(items)) {
throw new TypeError("购物项必须是数组");
}
return items.reduce((total, item) => {
// 检查商品格式是否正确
if (typeof item !== "object" || item === null) {
throw new TypeError("购物项必须是对象");
}
if (typeof item.price !== "number" || isNaN(item.price)) {
throw new TypeError(`商品 ${item.name || "未知"} 的价格必须是数字`);
}
if (typeof item.quantity !== "number" || !Number.isInteger(item.quantity) || item.quantity <= 0) {
throw new TypeError(`商品 ${item.name || "未知"} 的数量必须是正整数`);
}
return total + (item.price * item.quantity);
}, 0);
}
// 测试
const cartItems = [
{ name: "笔记本电脑", price: 5999, quantity: 1 },
{ name: "鼠标", price: 99.5, quantity: 2 },
{ name: "键盘", price: 249, quantity: 1 }
];
console.log(`购物车总金额: ¥${calculateCartTotal(cartItems)}`); // 购物车总金额: ¥6447
数据类型的内存表示
基本数据类型和引用数据类型在内存中的存储方式不同:
- 基本数据类型直接存储在栈内存中,占用空间小、大小固定,赋值时进行值复制。
- 引用数据类型在堆内存中存储数据本身,在栈内存中存储数据的引用(地址),占用空间大、大小不固定,赋值时只复制引用。
总结
JavaScript的数据类型系统是它灵活性的重要组成部分。虽然JavaScript是动态类型语言,但了解每种数据类型的特点和用法,对于编写高质量的JavaScript代码至关重要:
- 基本数据类型(Number、String、Boolean、Null、Undefined、Symbol、BigInt)直接表示简单的值。
- 引用数据类型(Object及其衍生如Array、Function、Date等)用于表示更复杂的数据结构。
- JavaScript提供了多种方法来检测和转换不同的数据类型。
- 理解类型转换规则可以避免许多常见错误。
掌握JavaScript的数据类型不仅是编写代码的基础,也是理解JavaScript更高级概念(如闭包、原型链等)的前提。
练习题
为了巩固所学知识,尝试完成以下练习:
- 创建一个函数,判断传入的参数是否是一个对象(不包括null)。
- 编写一个函数,接受任意类型的参数,并返回其详细的类型信息(不只是使用typeof)。
- 创建一个函数,可以深度比较两个值是否相等,包括处理对象和数组。
- 实现一个简单的类型安全的求和函数,只有当所有参数都是数字时才进行加法运算。
更多学习资源
继续深入学习JavaScript,探索更多高级主题!