变量与数据类型

在 JavaScript 中,变量声明与数据类型是构建程序的基础。ECMAScript 标准定义了三种变量声明方式,它们在作用域、生命周期及使用约束上存在显著差异,同时数据类型体系也通过原始类型与复合类型的划分,支撑了语言的灵活性与功能性。

变量声明方式与作用域特性

ECMAScript 提供的三种变量声明方式各具特点,直接影响代码的作用域管理与执行行为:

  • var:采用函数作用域或全局作用域,存在变量提升现象,即变量声明会被提升至作用域顶部,但赋值操作保留在原位置。这可能导致变量在声明前被访问时返回 undefined,引发逻辑错误。
  • let:引入块级作用域(以 {} 为边界),不存在变量提升,且不允许在同一作用域内重复声明。其生命周期仅限于所在代码块,有效避免了变量污染问题。
  • const:同样为块级作用域,用于声明常量。与 let 的核心区别在于,const 声明的变量必须在声明时初始化,且其指向的内存地址不可更改(对于原始类型值不可变,对于引用类型则禁止重新赋值,但属性可修改)[3]。

变量提升示例:使用 var 声明的变量会发生提升,而 let/const 则会触发暂时性死区(TDZ)。

javascript
复制代码
console.log(a); // undefined(var 声明提升)
var a = 10;

console.log(b); // 报错(let 未提升,处于 TDZ)
let b = 20;

数据类型体系与核心特性

JavaScript 数据类型分为原始类型复合类型两大类,二者在存储方式与访问机制上存在本质区别:

  • 原始类型:包括 Undefined、Null、Boolean、Number、BigInt、String、Symbol,采用值传递方式,存储于栈内存中。其中:
    • Symbol:通过 Symbol() 创建,具有唯一性,即使描述符相同的两个 Symbol 也不相等,常用于对象属性的唯一键,避免属性名冲突。
    • BigInt:通过数字后加 nBigInt() 构造,用于表示大于 Number 类型安全整数上限(2^53 - 1)的大整数,解决了传统 Number 类型在大整数运算中的精度丢失问题[4]。
  • 复合类型:主要为 Object,包括 Array、Function、Date 等子类,采用引用传递方式,存储于堆内存中,变量仅保存指向堆内存的引用地址[3]。

BigInt 应用场景:处理超过 Number 安全范围的整数运算,例如:

javascript
复制代码
const maxNumber = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(maxNumber + 1); // 9007199254740992(正确)
console.log(maxNumber + 2); // 9007199254740992(精度丢失)

const bigIntNum = BigInt(maxNumber) + 2n; // 9007199254740993n(BigInt 精确计算)
  • 复合类型:主要为 Object,包括 Array、Function、Date 等子类,采用引用传递方式,存储于堆内存中,变量仅保存指向堆内存的引用地址[3]。

类型判断与转换实践:用户信息注册案例

在实际开发中,类型判断与转换是数据校验的基础。以“用户信息注册”场景为例,需对用户输入的姓名、年龄、手机号等数据进行类型校验与转换:

类型判断方法

  • typeof:适用于原始类型判断(返回 'undefined'、'boolean'、'number'、'string'、'symbol'、'bigint'、'function'),但对 Null 会返回 'object',对 Array 等对象类型返回 'object'。
  • instanceof:适用于复合类型判断,通过原型链检测对象是否为某个构造函数的实例(如 [] instanceof Array 返回 true)。

类型转换方法

  • Number()/String():显式转换函数,例如将用户输入的年龄字符串转换为数字 Number(ageStr),或将手机号数字转换为字符串 String(phoneNum)
  • 隐式转换:通过运算符触发,如 '10' - 5 会隐式将字符串转为数字,但建议优先使用显式转换以保证代码可读性。

用户信息校验示例

javascript
复制代码
function registerUser(name, ageStr, phoneNum) {
  // 类型判断
  if (typeof name !== 'string' || name.trim() === '') {
    throw new Error('姓名必须为非空字符串');
  }
  
  // 类型转换与校验
  const age = Number(ageStr);
  if (isNaN(age) || age < 0 || age > 150) {
    throw new Error('年龄必须为有效数字(0-150)');
  }
  
  const phone = String(phoneNum);
  if (!/^1[3-9]\d{9}$/.test(phone)) {
    throw new Error('手机号格式错误');
  }
  
  return { name, age, phone };
}

通过合理选择变量声明方式、理解数据类型特性,并结合类型判断与转换工具,可有效提升代码的健壮性与可维护性,为复杂业务逻辑奠定坚实基础。