知识篇 -- JS变量与数据类型
在JavaScript编程中,变量是存储数据的容器,而数据类型则定义了这些数据可以表示的值的种类。理解变量的声明方式及其背后的机制,以及JavaScript的各种数据类型,是编写有效、健壮代码的第一步。
# 一、变量:数据的容器 核心
变量允许我们给数据一个名字,方便在程序中引用和操作这些数据。JavaScript提供了三种声明变量的方式:var、let 和 const。
# 1. var:老旧的声明方式 (ES5及之前) 不推荐
- 特点:
- 函数作用域:
var声明的变量只在函数内部有效,在函数外部无法访问。如果在函数外部声明,则为全局变量。 - 变量提升 (Hoisting):
var声明的变量会被提升到其所在作用域的顶部,但赋值操作不会被提升。这意味着你可以在声明之前使用var变量,但其值为undefined。 - 可重复声明:在同一个作用域内,可以重复声明同名
var变量,后面的声明会覆盖前面的。
- 函数作用域:
- 示例:
console.log(a); // undefined (变量提升) var a = 10; console.log(a); // 10 function testVar() { var b = 20; console.log(b); // 20 var b = 30; // 可重复声明 console.log(b); // 30 } testVar(); // console.log(b); // ReferenceError: b is not defined (函数作用域) - 缺点:
var的这些特性(尤其是变量提升和可重复声明)容易导致意外的错误和代码难以维护,因此在现代JavaScript开发中,推荐使用let和const。
# 2. let:块级作用域的变量 (ES6新增) 推荐
- 特点:
- 块级作用域:
let声明的变量只在当前代码块({}内部)有效。 - 无变量提升:
let变量不会被提升,在声明之前使用会报错(暂时性死区)。 - 不可重复声明:在同一个块级作用域内,不允许重复声明同名
let变量。
- 块级作用域:
- 示例:
// console.log(x); // ReferenceError: Cannot access 'x' before initialization (暂时性死区) let x = 10; console.log(x); // 10 if (true) { let y = 20; console.log(y); // 20 // let y = 30; // SyntaxError: Identifier 'y' has already been declared } // console.log(y); // ReferenceError: y is not defined (块级作用域) - 优点:
let解决了var的许多问题,使得变量管理更加严谨和可控。
# 3. const:常量 (ES6新增) 推荐
- 特点:
- 块级作用域:与
let相同,具有块级作用域。 - 无变量提升:与
let相同,存在暂时性死区。 - 不可重复声明:与
let相同,不允许重复声明。 - 声明时必须初始化:
const声明的变量必须在声明时赋值。 - 赋值后不可再修改:一旦赋值,就不能再重新赋值。
- 块级作用域:与
- 示例:
const PI = 3.14; // PI = 3.14159; // TypeError: Assignment to constant variable. const obj = { name: "Alice" }; obj.name = "Bob"; // 对象的属性可以修改 // obj = { name: "Charlie" }; // TypeError: Assignment to constant variable. - 注意:
const保证的是变量指向的那个内存地址不能改变,而不是变量的值不能改变。对于基本数据类型,值存储在变量指向的地址,所以值不能变。对于引用数据类型(如对象、数组),变量指向的是内存地址,该地址不能变,但地址中存储的对象内容是可以修改的。
# 二、数据类型:数据的分类 基础
JavaScript中的数据类型分为两大类:基本数据类型 (Primitive Types) 和 引用数据类型 (Reference Types)。
# 1. 基本数据类型 (Primitive Types) 不可变
基本数据类型的值直接存储在变量访问的位置,它们是不可变的(immutable),即一旦创建就不能被修改。
- String (字符串):表示文本数据。
- 示例:
"Hello World",'JavaScript',`Template Literal`
- 示例:
- Number (数字):表示整数或浮点数。
- 示例:
10,3.14,-5,NaN(Not a Number),Infinity
- 示例:
- Boolean (布尔值):表示逻辑实体,只有两个值:
true和false。- 示例:
true,false
- 示例:
- Null (空值):表示一个空对象指针,只有一个值
null。- 示例:
null
- 示例:
- Undefined (未定义):表示变量已声明但未赋值,只有一个值
undefined。- 示例:
let x; console.log(x); // undefined
- 示例:
- Symbol (符号) (ES6新增):表示独一无二的值,主要用于对象的属性键。
- 示例:
const sym = Symbol('description');
- 示例:
- BigInt (大整数) (ES2020新增):表示任意精度的整数。
- 示例:
10n,BigInt(100)
- 示例:
# 2. 引用数据类型 (Reference Types) 可变
引用数据类型的值存储在堆内存中,变量存储的是指向这些值的内存地址。它们是可变的(mutable),可以通过引用来修改其内容。
- Object (对象):表示键值对的集合,是JavaScript中最基本也是最重要的引用类型。
- 示例:
{ name: "Alice", age: 30 }
- 示例:
- Array (数组):表示有序的元素集合,是特殊的对象。
- 示例:
[1, 2, 3],["apple", "banana"]
- 示例:
- Function (函数):表示可执行的代码块,也是特殊的对象。
- 示例:
function greet() { /* ... */ }
- 示例:
- Date (日期):表示日期和时间。
- RegExp (正则表达式):表示正则表达式。
基本数据类型与引用数据类型的区别: 重要
| 特性 | 基本数据类型 | 引用数据类型 |
|---|---|---|
| 存储方式 | 直接存储在栈内存中 | 存储在堆内存中,栈内存中存储的是指向堆内存的地址 |
| 赋值方式 | 值复制:赋值后两个变量互不影响 | 引用复制:赋值后两个变量指向同一个对象,一个改变另一个也改变 |
| 比较方式 | 值比较:只有值相等才相等 | 引用比较:只有指向同一个内存地址才相等 |
| 可变性 | 不可变:值一旦创建就不能被修改 | 可变:可以通过引用修改其内容 |
示例:
// 基本数据类型赋值
let num1 = 10;
let num2 = num1;
num2 = 20;
console.log(num1); // 10
console.log(num2); // 20
// 引用数据类型赋值
let obj1 = { value: 10 };
let obj2 = obj1;
obj2.value = 20;
console.log(obj1.value); // 20
console.log(obj2.value); // 20
理解JavaScript的变量声明方式和数据类型是掌握这门语言的基础。合理选择 var、let、const,并区分基本类型和引用类型,能帮助你写出更清晰、更少bug的代码。