JavaScript 变量详解
个人主页:康师傅前端面馆
在 JavaScript 编程中,变量是存储数据的基本容器,它在代码里扮演着至关重要的角色。无论是简单的数值计算,还是复杂的对象操作,都离不开变量的使用。理解 JavaScript 变量的各种特性、使用方法以及容易遇到的陷阱,对于编写高质量、可维护的代码至关重要。本文将详细介绍 JavaScript 变量的基本用法、内置变量和保留字、变量提升、易错问题以及最佳实践,帮助你全面掌握 JavaScript 变量的相关知识。
一、变量的基本用法
1. 声明变量
在 JavaScript 中,我们使用 var
、let
和 const
来声明变量。
var
:传统方式,函数作用域
javascript
var name = "Alice";
let
:ES6 引入,块级作用域,可重新赋值
javascript
let age = 25;
age = 30; // 合法
const
:ES6 引入,块级作用域,不可重新赋值(注意:如果是对象或数组,其内容可以修改)
javascript
const PI = 3.14;
// PI = 3.1415; // 报错:Assignment to constant variable.
2. 变量命名规则
- 可以包含字母、数字、下划线
_
、美元符号$
- 不能以数字开头
- 区分大小写
- 不建议使用保留字作为变量名
javascript
let userName = "Bob"; // 推荐使用驼峰命名法
let user_name = "Bob";
let $price = 19.99;
let _count = 10;
二、内置变量和保留字
JavaScript 提供了一些预定义的全局变量或属性,它们在运行环境中自动存在,无需显式声明。这些变量通常用于表示基础值、类型或执行上下文信息。
1. 特殊值变量
变量名 | 类型 | 描述 |
---|---|---|
undefined |
undefined |
表示变量未被赋值 |
NaN |
number |
表示"非数字"(Not-a-Number),如 'abc' - 1 的结果 |
Infinity |
number |
表示正无穷大,如 1 / 0 |
-Infinity |
number |
表示负无穷大,如 -1 / 0 |
⚠️ 注意:
NaN !== NaN
,应使用Number.isNaN()
判断。
javascript
console.log(NaN === NaN); // false
console.log(Number.isNaN(NaN)); // true
2. 全局对象属性
ECMAScript 标准中定义的全局属性也被视为"内置变量",例如:
eval
: 函数,用于执行字符串形式的 JavaScript 代码parseInt
,parseFloat
: 用于解析数字字符串decodeURI
,encodeURI
等:处理 URI 编码
javascript
let numStr = "123px";
let num = parseInt(numStr); // 123
✅ 建议: 避免覆盖这些内置变量,否则可能导致程序异常。
3. 保留字
JavaScript 中有一些关键字是保留字,不能作为变量名、函数名或对象属性名使用。它们是语言语法的一部分,用于控制流程、定义结构等。 以下是部分 ES6+ 常见关键字列表:
plaintext
break case catch class const continue
debugger default delete do else enum
export extends false finally for function
if import in instanceof let new
null return super switch this throw
true try typeof var void while
with yield await async
⚠️ 错误示例:
javascript
let class = "Math"; // SyntaxError: Unexpected token 'class'
4. 未来保留字
即使某些词目前不是关键字,在未来版本中可能成为关键字,因此也禁止用作标识符:
plaintext
implements interface let package private
protected public static yield
✅ 建议: 使用工具如 ESLint 检查命名是否合法。
三、变量提升
JavaScript 在执行代码前会进行编译阶段,在这个阶段中变量和函数声明会被"提升"到当前作用域顶部。
1. var
提升
javascript
console.log(name); // undefined
var name = "Alice";
// 实际相当于:
var name;
console.log(name); // undefined
name = "Alice";
2. let
和 const
提升
虽然也会被提升,但不会被初始化,因此访问它们会触发 暂时性死区 (Temporal Dead Zone, TDZ) 错误。
javascript
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 25;
四、易错问题
1. 未声明就使用变量(全局污染)
javascript
function sayHello() {
message = "Hello"; // 未使用 var/let/const 声明,变成了全局变量
}
sayHello();
console.log(message); // "Hello"
✅ 建议: 总是使用
let
或const
显式声明变量。
2. typeof
返回 "object"
的陷阱
javascript
console.log(typeof null); // "object" ------ 这是一个历史遗留错误
console.log(typeof []); // "object"
✅ 建议: 使用
Array.isArray()
判断数组,使用=== null
判断 null。
3. 浮点数精度问题
javascript
console.log(0.1 + 0.2 === 0.3); // false
✅ 建议: 对浮点运算保持警惕,必要时使用
Number.EPSILON
或第三方库处理。
4. NaN
的判断
javascript
console.log(NaN === NaN); // false
✅ 建议: 使用
Number.isNaN()
而不是全局的isNaN()
函数。
javascript
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("abc")); // false
5. 类型自动转换带来的问题
javascript
console.log("5" - 3); // 2
console.log("5" + 3); // "53"
console.log("5" < 6); // true
✅ 建议: 明确数据类型,避免隐式类型转换造成的困惑。
五、最佳实践总结
实践建议 | 说明 |
---|---|
不要使用保留字作为变量名 | 否则会导致语法错误或兼容性问题 |
避免覆盖内置变量 | 如 undefined 、NaN 、eval 等 |
使用 const 和 let 替代 var |
更安全的作用域控制 |
使用严格模式 "use strict" |
可以防止一些不安全的操作 |
使用 Linter 工具检查命名 | 如 ESLint 可自动检测非法命名 |