1.1.1 Number类型
概念解释
- 定义:表示整数和浮点数的数字类型
- 特点:采用IEEE 754标准的64位双精度浮点数
- 范围:-(2^53 - 1) 到 (2^53 - 1)
详细说明
// 1. 数字字面量
const integer = 42; // 整数
const float = 42.42; // 浮点数
const scientific = 3e8; // 科学计数法
const binary = 0b1010; // 二进制
const octal = 0o744; // 八进制
const hex = 0xFF; // 十六进制
// 2. 特殊值
const infinity = Infinity; // 无穷大
const negInfinity = -Infinity; // 负无穷大
const notANumber = NaN; // 非数字
// 3. 数字操作
const sum = 0.1 + 0.2; // 注意:浮点数精度问题
console.log(sum); // 0.30000000000000004
// 4. 数字方法
const num = 42.42;
console.log(num.toFixed(1)); // "42.4"
console.log(num.toPrecision(3)); // "42.4"
console.log(Number.isInteger(num)); // false
常见错误及最佳实践
// 错误示例1:浮点数比较
if (0.1 + 0.2 === 0.3) { // 永远不会为true
console.log("相等");
}
// 正确做法:使用极小值比较
const epsilon = 0.00001;
if (Math.abs((0.1 + 0.2) - 0.3) < epsilon) {
console.log("近似相等");
}
// 错误示例2:检查NaN
if (someValue === NaN) { // 永远不会为true
console.log("是NaN");
}
// 正确做法:使用Number.isNaN()
if (Number.isNaN(someValue)) {
console.log("是NaN");
}
// 错误示例3:数字运算溢出
const bigNumber = 9999999999999999; // 精度丢失
// 正确做法:使用BigInt
const safeBigNumber = 9999999999999999n;
注意事项
-
精度限制
- 整数精确表示范围:±2^53
- 浮点数计算可能存在精度误差
- 需要高精度计算时考虑使用专门的库(如decimal.js)
-
性能考虑
- 整数运算比浮点数运算快
- 位运算仅适用于32位整数
- 大数运算考虑使用BigInt
-
类型转换
// 字符串转数字
const num1 = Number("42"); // 推荐
const num2 = +"42"; // 简写方式
const num3 = parseInt("42"); // 解析整数
const num4 = parseFloat("42.42"); // 解析浮点数
// 数字转字符串
const str1 = String(42); // 推荐
const str2 = 42 + ""; // 不推荐:隐式转换
const str3 = (42).toString(); // 对象方法
扩展知识
- Number对象的静态属性
Number.MAX_VALUE // 最大数值
Number.MIN_VALUE // 最小数值
Number.MAX_SAFE_INTEGER // 最大安全整数
Number.MIN_SAFE_INTEGER // 最小安全整数
Number.EPSILON // 最小精度
- 数字格式化
// 使用Intl.NumberFormat进行本地化格式化
const formatter = new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
});
console.log(formatter.format(42.42)); // ¥42.42
// 科学计数法
const bigNum = 1e6;
console.log(bigNum.toExponential()); // "1e+6"
- 现代JavaScript特性
// 数字分隔符(ES2021)
const billion = 1_000_000_000; // 更易读的数字表示
// BigInt用于大数运算
const bigInt = 9007199254740991n;
const result = bigInt + 1n;
实际应用场景
- 金融计算
// 不推荐
const price = 0.1 + 0.2;
// 推荐:使用整数计算后再转换
function calculatePrice(price1, price2) {
// 转换为分进行计算
const cents1 = Math.round(price1 * 100);
const cents2 = Math.round(price2 * 100);
const totalCents = cents1 + cents2;
return totalCents / 100;
}
console.log(calculatePrice(0.1, 0.2)); // 0.3
- 科学计算
// 计算圆的面积
function calculateCircleArea(radius) {
if (typeof radius !== 'number' || radius < 0) {
throw new Error('半径必须是正数');
}
return Math.PI * Math.pow(radius, 2);
}
// 带精度控制的计算
function calculateWithPrecision(value, precision = 2) {
return Number(Math.round(value + 'e' + precision) + 'e-' + precision);
}
1.1.2 String类型
概念解释
- 定义:表示文本数据的字符序列
- 特点:不可变(immutable)、使用UTF-16编码
- 使用场景:文本处理、数据展示、模板生成
详细说明
1. 字符串创建
// 1. 字符串字面量
const single = 'single quotes';
const double = "double quotes";
const backticks = `template literal`;
// 2. String构造函数
const strObject = new String("string"); // 不推荐:会创建String对象
const strPrimitive = String("string"); // 推荐:显式转换为字符串
// 3. 模板字符串
const name = "张三";
const age = 25;
const greeting = `你好,我是${name},今年${age}岁`; // 支持插值表达式
// 4. 多行字符串
const multiLine = `
这是第一行
这是第二行
这是第三行
`; // 保留换行和缩进
// 5. 转义字符
const escaped = 'I\'m a string'; // 使用反斜杠转义
const newLine = 'First line\nSecond line'; // 特殊字符
2. 字符串操作方法
const str = "Hello, World!";
// 1. 基本属性和访问
console.log(str.length); // 13
console.log(str[0]); // "H"
console.log(str.charAt(0)); // "H"(推荐)
// 2. 查找和位置
console.log(str.indexOf("o")); // 4
console.log(str.lastIndexOf("o")); // 7
console.log(str.includes("World")); // true
console.log(str.startsWith("Hello")); // true
console.log(str.endsWith("!")); // true
// 3. 提取子串
console.log(str.substring(0, 5)); // "Hello"
console.log(str.slice(0, 5)); // "Hello"
console.log(str.slice(-6)); // "World!"
// 4. 转换和替换
console.log(str.toUpperCase()); // "HELLO, WORLD!"
console.log(str.toLowerCase()); // "hello, world!"
console.log(str.replace("Hello", "Hi")); // "Hi, World!"
console.log(str.replaceAll("l", "L")); // "HeLLo, WorLd!"
// 5. 分割和合并
console.log(str.split(", ")); // ["Hello", "World!"]
console.log(["Hello", "World"].join(" ")); // "Hello World"
// 6. 去除空白
const spacedStr = " trim me ";
console.log(spacedStr.trim()); // "trim me"
console.log(spacedStr.trimStart()); // "trim me "
console.log(spacedStr.trimEnd()); // " trim me"
3. 高级字符串操作
// 1. 正则表达式匹配
const text = "Hello 123 World 456";
console.log(text.match(/\d+/g)); // ["123", "456"]
console.log(text.matchAll(/\d+/g)); // 返回迭代器
// 2. Unicode支持
const emoji = "😀";
console.log(emoji.length); // 2(因为使用UTF-16编码)
console.log([...emoji].length); // 1(正确的字符数)
// 3. 字符串填充
const num = "42";
console.log(num.padStart(5, "0")); // "00042"
console.log(num.padEnd(5, "0")); // "42000"
// 4. 重复字符串
console.log("abc".repeat(3)); // "abcabcabc"
常见错误及最佳实践:
// 错误示例1:字符串连接
let result = "";
for (let i = 0; i < 1000; i++) {
result += i; // 性能差:每次连接都创建新字符串
}
// 正确做法:使用数组join或模板字符串
const numbers = Array.from({length: 1000}, (_, i) => i);
result = numbers.join("");
// 或使用数组的reduce
result = numbers.reduce((acc, curr) => `${acc}${curr}`, "");
// 错误示例2:不当的字符串比较
if (userInput.toLowerCase() == "yes") { // 不推荐
// ...
}
// 正确做法:规范化后使用严格相等
const normalizedInput = userInput.trim().toLowerCase();
if (normalizedInput === "yes") {
// ...
}
// 错误示例3:使用eval解析字符串
const jsonStr = '{"name": "张三"}';
const obj = eval(jsonStr); // 危险:可能执行恶意代码
// 正确做法:使用JSON.parse
const safeObj = JSON.parse(jsonStr);
性能优化
// 1. 大量字符串拼接
const fragments = [];
for (let i = 0; i < 1000; i++) {
fragments.push(`Item ${i}`);
}
const result = fragments.join("");
// 2. 字符串搜索优化
const longText = "很长的文本...";
// 创建正则表达式对象一次
const regex = /pattern/g;
while (regex.exec(longText) !== null) {
// 处理匹配
}
// 3. 字符串缓存
const stringCache = new Map();
function getProcessedString(str) {
if (!stringCache.has(str)) {
stringCache.set(str, expensiveStringOperation(str));
}
return stringCache.get(str);
}
实际应用场景
// 1. URL处理
function parseQueryString(url) {
const queryString = url.split('?')[1];
if (!queryString) return {};
return queryString
.split('&')
.reduce((params, param) => {
const [key, value] = param.split('=');
params[decodeURIComponent(key)] = decodeURIComponent(value);
return params;
}, {});
}
// 2. 模板引擎简单实现
function templateFn(str, data) {
return str.replace(/\${(\w+)}/g, (match, key) => {
return data[key] || '';
});
}
const template = "Hello, ${name}! You are ${age} years old.";
const data = { name: "张三", age: 25 };
console.log(templateFn(template, data)); // Hello, 张三! You are 25 years old.
// 3. 文本格式化
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
console.log(formatNumber(1234567)); // "1,234,567"
注意事项
-
字符串不可变性
- 所有字符串操作都会返回新字符串
- 原字符串永远不会被修改
- 频繁的字符串操作要注意性能
-
编码问题
- 使用UTF-16编码
- 某些字符(如emoji)占用两个代码单元
- 使用专门的库处理复杂的Unicode操作
-
安全考虑
- 避免使用eval()处理字符串
- 注意XSS攻击风险
- 使用适当的转义处理用户输入
1.1.3 Boolean类型
概念解释:
- 定义:表示逻辑值,只有true和false两个值
- 特点:用于条件判断和逻辑运算
- 使用场景:条件控制、标志位、状态判断
详细说明
1. Boolean值的创建和转换
// 1. 直接声明
const isActive = true;
const isLoading = false;
// 2. Boolean构造函数
const boolObject = new Boolean(true); // 不推荐:创建Boolean对象
const boolPrimitive = Boolean(1); // 推荐:显式转换
// 3. 双重否定转换
const isTrue = !!"非空字符串"; // true
const isFalse = !!""; // false
// 4. 各种类型转换为布尔值的规则
console.log(Boolean("")); // false
console.log(Boolean("0")); // true
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean({})); // true
console.log(Boolean([])); // true
2. 逻辑运算
// 1. 基本逻辑运算
const a = true;
const b = false;
console.log(a && b); // false
console.log(a || b); // true
console.log(!a); // false
// 2. 短路运算
const obj = null;
const name = obj && obj.name; // null(安全访问)
const defaultName = name || "默认名称"; // "默认名称"
// 3. 空值合并运算符
const value = null;
const result = value ?? "默认值"; // "默认值"
3. 条件判断最佳实践
// 1. 显式布尔检查
function isValidUser(user) {
// 明确的布尔返回值
return Boolean(
user &&
user.id &&
user.name &&
user.email
);
}
// 2. 使用Array.some()和Array.every()
const numbers = [1, 2, 3, 4, 5];
const hasEven = numbers.some(num => num % 2 === 0); // true
const allPositive = numbers.every(num => num > 0); // true
// 3. 状态标志管理
class TaskManager {
#isRunning = false;
start() {
if (this.#isRunning) {
throw new Error('Task is already running');
}
this.#isRunning = true;
// 执行任务...
}
stop() {
this.#isRunning = false;
}
}
常见错误及最佳实践:
// 错误示例1:隐式类型转换
if ("0") {
console.log("这会执行,因为非空字符串转换为true");
}
// 正确做法:显式转换或比较
if (value === "0") {
console.log("精确的字符串比较");
}
// 错误示例2:误用逻辑运算符
const value = 0;
const result = value || 42; // 会返回42,可能不是想要的结果
// 正确做法:使用空值合并运算符
const safeResult = value ?? 42; // 会返回0
// 错误示例3:复杂条件判断
if (value && value.length && value.length > 0 && value[0]) {
// 难以维护的条件判断
}
// 正确做法:封装判断逻辑
function isValidValue(value) {
return Array.isArray(value) && value.length > 0 && Boolean(value[0]);
}
if (isValidValue(value)) {
// 更清晰的代码
}
1.1.4 Null类型
概念解释
- 定义:表示"空"或"不存在"的特殊值
- 特点:只有一个值null
- 使用场景:表示对象的空值、初始化变量、函数返回值
详细说明
// 1. null的基本使用
let user = null; // 明确表示对象不存在
// 2. null的类型检查
console.log(typeof null); // "object"(JavaScript的一个历史遗留bug)
console.log(Object.prototype.toString.call(null)); // "[object Null]"
// 3. null的相等性
console.log(null == undefined); // true(宽松相等)
console.log(null === undefined); // false(严格相等)
// 4. 空值合并运算符与null
const value = null;
const result = value ?? "default"; // "default"
最佳实践
// 1. 初始化对象引用
class UserManager {
#currentUser = null; // 明确表示没有当前用户
login(user) {
this.#currentUser = user;
}
logout() {
this.#currentUser = null; // 显式清除引用
}
}
// 2. 函数返回值
function findUser(id) {
const user = database.find(id);
return user || null; // 明确返回null表示未找到
}
// 3. 参数验证
function processUser(user) {
if (user === null) {
throw new Error('User cannot be null');
}
// 处理用户...
}
1.1.5 Undefined类型
概念解释
- 定义:表示未定义或不存在的值
- 特点:全局只有一个undefined值
- 使用场景:变量未赋值、函数无返回值、对象不存在的属性
详细说明
// 1. undefined的产生情况
let variable; // 自动获得undefined值
function noReturn() {} // 函数隐式返回undefined
const obj = {};
console.log(obj.nonexistent); // undefined
// 2. undefined的检查
console.log(typeof undefined); // "undefined"
console.log(void 0); // undefined(获取undefined的安全方式)
// 3. 可选链操作符
const user = undefined;
console.log(user?.name); // undefined(安全访问)
最佳实践和注意事项
// 1. 参数默认值
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
// 2. 属性检查
const obj = { a: 1 };
// 不推荐
if (obj.b !== undefined) {
// 处理...
}
// 推荐
if ('b' in obj) {
// 处理...
}
// 3. undefined vs null的使用
// undefined:表示系统级别的、出乎意料的或类型错误的值
// null:表示程序级别的、意料之中的或正常情况的空值
// 示例
class Cache {
get(key) {
const value = this.storage.get(key);
return value === undefined ? null : value;
}
set(key, value) {
if (value === null) {
throw new Error('Value cannot be null');
}
this.storage.set(key, value);
}
}
安全考虑和防御性编程
// 1. 安全的undefined检查
function isUndefined(value) {
return value === void 0;
}
// 2. 防御性编程示例
function processData(data) {
// 参数验证
if (data === undefined) {
throw new TypeError('Data is required');
}
// 安全的属性访问
const name = data?.name ?? 'Unknown';
const age = data?.age ?? 0;
// 类型检查
if (typeof name !== 'string') {
throw new TypeError('Name must be a string');
}
if (typeof age !== 'number') {
throw new TypeError('Age must be a number');
}
return {
name,
age
};
}
让我们继续讲解Symbol和BigInt这两种现代JavaScript的基本数据类型。
1.1.6 Symbol类型
概念解释
- 定义:表示唯一的标识符
- 特点:每个Symbol值都是独一无二的
- 使用场景:唯一属性键、常量值、防止属性名冲突
详细说明
1. Symbol的创建和使用
// 1. 基本创建
const sym1 = Symbol();
const sym2 = Symbol('description'); // 带描述的Symbol
const sym3 = Symbol('description'); // 注意:sym2 !== sym3
// 2. Symbol.for - 全局Symbol注册
const globalSym1 = Symbol.for('globalKey');
const globalSym2 = Symbol.for('globalKey');
console.log(globalSym1 === globalSym2); // true
// 3. 获取Symbol描述
console.log(sym2.description); // "description"
console.log(Symbol.keyFor(globalSym1)); // "globalKey"
// 4. Symbol作为对象属性
const MY_KEY = Symbol('my_key');
const obj = {
[MY_KEY]: 'value',
regularKey: 'regular value'
};
// 访问Symbol属性
console.log(obj[MY_KEY]); // "value"
2. Symbol的高级用法
// 1. 内置Symbol值
class CustomIterator {
// 自定义迭代器
[Symbol.iterator]() {
let count = 0;
return {
next() {
return count < 3
? { value: count++, done: false }
: { done: true };
}
};
}
// 自定义类型转换
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number':
return 123;
case 'string':
return 'CustomIterator';
default:
return true;
}
}
}
// 2. Symbol用于私有属性(ES2019之前的方案)
const _private = Symbol('private');
class MyClass {
constructor() {
this[_private] = 'private value';
}
getPrivateValue() {
return this[_private];
}
}
// 3. Symbol.species
class SpecialArray extends Array {
static get [Symbol.species]() {
return Array; // 确保map等操作返回普通数组
}
}
3. 实际应用场景
// 1. 状态管理中的action类型
const ActionTypes = {
INCREMENT: Symbol('INCREMENT'),
DECREMENT: Symbol('DECREMENT'),
RESET: Symbol('RESET')
};
function reducer(state, action) {
switch (action.type) {
case ActionTypes.INCREMENT:
return state + 1;
case ActionTypes.DECREMENT:
return state - 1;
case ActionTypes.RESET:
return 0;
default:
return state;
}
}
// 2. 插件系统中的钩子
class Plugin {
static hooks = {
BEFORE_INIT: Symbol('BEFORE_INIT'),
AFTER_INIT: Symbol('AFTER_INIT'),
BEFORE_DESTROY: Symbol('BEFORE_DESTROY')
};
constructor() {
this.listeners = new Map();
}
addHook(hook, callback) {
if (!this.listeners.has(hook)) {
this.listeners.set(hook, new Set());
}
this.listeners.get(hook).add(callback);
}
}
// 3. 元数据存储
const metadata = Symbol('metadata');
class User {
constructor(name) {
this[metadata] = {
created: Date.now(),
id: Math.random().toString(36).substr(2, 9)
};
this.name = name;
}
getMetadata() {
return this[metadata];
}
}
注意事项和最佳实践:
// 1. Symbol属性的遍历
const obj = {
[Symbol('a')]: 'a',
[Symbol('b')]: 'b',
c: 'c'
};
// Symbols不会出现在普通遍历中
console.log(Object.keys(obj)); // ['c']
console.log(Object.getOwnPropertyNames(obj)); // ['c']
// 获取Symbol属性
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(a), Symbol(b)]
console.log(Reflect.ownKeys(obj)); // [Symbol(a), Symbol(b), 'c']
// 2. Symbol与JSON
const objWithSymbol = {
[Symbol('key')]: 'value',
regular: 'normal'
};
// Symbol属性会被忽略
console.log(JSON.stringify(objWithSymbol)); // {"regular":"normal"}
// 3. 内存管理
// 不使用Symbol.for时,Symbol不会被垃圾回收
const potentialLeak = [];
function createSymbol() {
const sym = Symbol('temp');
potentialLeak.push(sym);
}
// 使用WeakMap存储Symbol相关数据
const symbolData = new WeakMap();
function safeSymbolData(sym, data) {
symbolData.set(sym, data);
}
1.1.7 BigInt类型
概念解释
- 定义:表示任意精度的整数
- 特点:可以安全地存储和操作大整数
- 使用场景:大数计算、精确时间戳、加密计算
详细说明
1. BigInt的创建和基本操作
// 1. 创建BigInt
const bigInt1 = 9007199254740991n; // 使用n后缀
const bigInt2 = BigInt("9007199254740991"); // 使用构造函数
const bigIntFromNumber = BigInt(Number.MAX_SAFE_INTEGER);
// 2. 基本运算
const sum = bigInt1 + bigInt2;
const product = bigInt1 * 2n;
const power = bigInt1 ** 2n;
// 3. 比较操作
console.log(1n < 2n); // true
console.log(2n > 1); // true
console.log(2n == 2); // true
console.log(2n === 2); // false(严格相等会检查类型)
2. 实际应用场景
// 1. 精确时间计算
class PreciseTimer {
static now() {
// 获取纳秒级时间戳
return BigInt(process.hrtime.bigint());
}
static calculateDuration(start, end) {
return (end - start) / BigInt(1000000); // 转换为毫秒
}
}
// 2. 大数运算
function factorial(n) {
if (n === 0n) return 1n;
return n * factorial(n - 1n);
}
console.log(factorial(50n));
// 3. 金融计算(处理大额数字)
class FinancialCalculator {
static toCents(dollars) {
return BigInt(Math.round(dollars * 100));
}
static fromCents(cents) {
return Number(cents) / 100;
}
static addMoney(amount1, amount2) {
const cents1 = this.toCents(amount1);
const cents2 = this.toCents(amount2);
return this.fromCents(cents1 + cents2);
}
}