变量与常量 #
一、变量概述 #
在Deno中,变量是存储数据的容器。Deno(以及JavaScript/TypeScript)提供了三种声明变量的方式:var、let 和 const。
二、let声明 #
2.1 基本用法 #
let 声明一个可重新赋值的块级作用域变量:
typescript
let name = "Deno";
console.log(name); // Deno
name = "TypeScript"; // 可以重新赋值
console.log(name); // TypeScript
2.2 块级作用域 #
let 声明的变量具有块级作用域:
typescript
if (true) {
let blockScoped = "只在块内可见";
console.log(blockScoped); // 只在块内可见
}
// console.log(blockScoped); // 错误:blockScoped未定义
2.3 暂时性死区 #
let 声明的变量在声明前不可访问:
typescript
// console.log(x); // 错误:无法在声明前访问
let x = 10;
console.log(x); // 10
2.4 不允许重复声明 #
同一作用域内不能重复声明:
typescript
let x = 10;
// let x = 20; // 错误:不能重复声明
2.5 TypeScript类型注解 #
typescript
let name: string = "Deno";
let version: number = 2.0;
let isActive: boolean = true;
// 类型推断
let city = "Beijing"; // 自动推断为string类型
// city = 100; // 错误:不能将number赋值给string
三、const声明 #
3.1 基本用法 #
const 声明一个不可重新赋值的块级作用域常量:
typescript
const PI = 3.14159;
console.log(PI); // 3.14159
// PI = 3.14; // 错误:不能重新赋值
3.2 必须初始化 #
const 声明时必须赋值:
typescript
const x = 10; // 正确
// const y; // 错误:必须初始化
3.3 对象的可变性 #
const 只保证变量引用不变,对象属性仍可修改:
typescript
const user = {
name: "Alice",
age: 25
};
user.age = 26; // 允许修改属性
user.email = "alice@example.com"; // 允许添加属性
console.log(user); // { name: "Alice", age: 26, email: "alice@example.com" }
// user = {}; // 错误:不能重新赋值
3.4 数组的可变性 #
typescript
const numbers = [1, 2, 3];
numbers.push(4); // 允许
numbers[0] = 10; // 允许
console.log(numbers); // [10, 2, 3, 4]
// numbers = []; // 错误:不能重新赋值
3.5 冻结对象 #
使用 Object.freeze() 创建真正的不可变对象:
typescript
const frozenUser = Object.freeze({
name: "Bob",
age: 30
});
// frozenUser.age = 31; // 严格模式下报错
// frozenUser.email = "bob@example.com"; // 严格模式下报错
console.log(Object.isFrozen(frozenUser)); // true
四、var声明 #
4.1 基本用法 #
var 是ES5及之前的变量声明方式,存在一些问题:
typescript
var name = "Deno";
console.log(name); // Deno
name = "Node"; // 可以重新赋值
console.log(name); // Node
4.2 函数作用域 #
var 声明的变量是函数作用域:
typescript
function test() {
if (true) {
var x = 10; // 函数作用域
}
console.log(x); // 10,可以访问
}
test();
// console.log(x); // 错误:x未定义
4.3 变量提升 #
var 声明的变量会被提升到函数顶部:
typescript
console.log(hoisted); // undefined(不是错误)
var hoisted = "我被提升了";
// 等价于:
// var hoisted;
// console.log(hoisted);
// hoisted = "我被提升了";
4.4 允许重复声明 #
typescript
var x = 10;
var x = 20; // 允许,但可能导致bug
console.log(x); // 20
4.5 避免使用var #
由于 var 的作用域和提升问题,建议使用 let 和 const 替代:
typescript
// 不推荐
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:3, 3, 3
// 推荐
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:0, 1, 2
五、变量命名规则 #
5.1 合法命名 #
typescript
// 合法命名
let name = "Deno";
let firstName = "John";
let _private = true;
let $jquery = "library";
let name1 = "first";
let 名字 = "中文"; // 允许但不推荐
5.2 非法命名 #
typescript
// 非法命名
// let 1name = "error"; // 不能以数字开头
// let my-name = "error"; // 不能包含连字符
// let class = "error"; // 不能使用保留字
5.3 命名约定 #
typescript
// 小驼峰命名(变量、函数)
let userName = "Alice";
let isActive = true;
// 大驼峰命名(类、构造函数)
class UserProfile {
name: string;
}
// 全大写下划线(常量)
const MAX_SIZE = 100;
const API_BASE_URL = "https://api.example.com";
// 下划线前缀(私有属性约定)
let _internalValue = 0;
六、解构赋值 #
6.1 数组解构 #
typescript
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// 跳过元素
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
// 剩余元素
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// 默认值
const [x = 0, y = 0] = [10];
console.log(x, y); // 10 0
6.2 对象解构 #
typescript
const user = {
name: "Alice",
age: 25,
city: "Beijing"
};
const { name, age } = user;
console.log(name, age); // Alice 25
// 重命名
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // Alice 25
// 默认值
const { name, country = "China" } = user;
console.log(country); // China
// 剩余属性
const { name, ...rest } = user;
console.log(rest); // { age: 25, city: "Beijing" }
6.3 嵌套解构 #
typescript
const data = {
user: {
name: "Alice",
address: {
city: "Beijing",
country: "China"
}
}
};
const { user: { name, address: { city } } } = data;
console.log(name, city); // Alice Beijing
6.4 函数参数解构 #
typescript
interface User {
name: string;
age: number;
}
function greet({ name, age }: User): string {
return `Hello, ${name}! You are ${age} years old.`;
}
console.log(greet({ name: "Alice", age: 25 }));
七、展开运算符 #
7.1 数组展开 #
typescript
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
const withExtra = [0, ...arr1, 3.5, ...arr2, 7];
console.log(withExtra); // [0, 1, 2, 3, 3.5, 4, 5, 6, 7]
// 复制数组
const copy = [...arr1];
console.log(copy); // [1, 2, 3]
7.2 对象展开 #
typescript
const defaults = {
theme: "dark",
language: "en",
debug: false
};
const userConfig = {
language: "zh",
debug: true
};
const config = { ...defaults, ...userConfig };
console.log(config);
// { theme: "dark", language: "zh", debug: true }
// 添加属性
const extended = { ...config, version: "1.0" };
console.log(extended);
八、变量作用域 #
8.1 全局作用域 #
typescript
const globalVar = "全局变量";
function showGlobal() {
console.log(globalVar); // 可以访问
}
showGlobal();
console.log(globalVar); // 可以访问
8.2 函数作用域 #
typescript
function test() {
const functionVar = "函数作用域";
console.log(functionVar);
}
test();
// console.log(functionVar); // 错误:无法访问
8.3 块级作用域 #
typescript
if (true) {
const blockVar = "块级作用域";
console.log(blockVar); // 可以访问
}
// console.log(blockVar); // 错误:无法访问
8.4 作用域链 #
typescript
const outer = "外部";
function outerFunc() {
const middle = "中间";
function innerFunc() {
const inner = "内部";
console.log(outer); // 外部
console.log(middle); // 中间
console.log(inner); // 内部
}
innerFunc();
}
outerFunc();
九、最佳实践 #
9.1 优先使用const #
typescript
// 推荐
const PI = 3.14159;
const config = { debug: true };
const users = ["Alice", "Bob"];
// 需要重新赋值时使用let
let count = 0;
count++;
// 避免使用var
// var x = 10; // 不推荐
9.2 就近声明 #
typescript
// 推荐:在使用前声明
function process(data: string) {
const trimmed = data.trim();
const upper = trimmed.toUpperCase();
return upper;
}
// 不推荐:在函数开头声明所有变量
function processBad(data: string) {
let trimmed: string;
let upper: string;
trimmed = data.trim();
upper = trimmed.toUpperCase();
return upper;
}
9.3 合理命名 #
typescript
// 好的命名
const userCount = 10;
const isLoggedIn = true;
const fetchUserData = async () => {};
// 不好的命名
const x = 10;
const flag = true;
const func = async () => {};
十、总结 #
本章学习了:
let声明可变变量const声明常量var的问题与避免使用- 变量命名规则与约定
- 解构赋值
- 展开运算符
- 变量作用域
- 最佳实践
下一章,我们将学习基本数据类型。
最后更新:2026-03-28