JavaScript基础语法实例:变量、循环与函数代码演示
深入浅出解析JavaScript核心基础语法:变量声明机制(var/let/const)、三大常用循环结构(for/while/for...of)及函数定义与参数传递,配合完整代码示例与高清内联图解。
let/const/var 的声明机制与内存边界、传统与现代循环结构的选型依据,以及各类函数的定义方式与参数传递技巧,帮助读者建立扎实且符合现代规范的 JavaScript 编码能力。
一、变量声明与内存绑定:let、const 与 var 的本质机制
在 JavaScript 中,变量是存放数据或值引用的具名存储空间。自 ECMAScript 2015 (ES6) 引入 let 与 const 之后,传统的 var 声明在现代工程中已逐渐被取代。理解它们在作用域划分、变量提升以及重复声明规则上的差异,是避免代码逻辑异常与内存泄漏的前提。
1. 作用域与声明机制详解
var 遵循函数作用域规则,这意味着只要在函数内部声明,哪怕位于某个 if 分支或循环体中,该变量也会在整个函数内有效;而在全局上下文中声明时,它还会直接挂载到全局对象(如浏览器的 window)上。相反,let 和 const 具备严格的块级作用域(以花括号 { ... } 为界限),能够有效防止变量穿透代码块污染外部状态。
// 1. 作用域隔离对比
function testScope() {
if (true) {
var legacyVar = "var会穿透代码块";
let modernLet = "let被严格限制在块内";
const modernConst = "const同样受限于块内";
}
console.log(legacyVar); // 正常输出: "var会穿透代码块"
// 下面两行若解除注释将直接抛出 ReferenceError 错误:
// console.log(modernLet);
// console.log(modernConst);
}
testScope();
2. 变量提升与暂时性死区(TDZ)
许多初学者常听闻“let 和 const 不会发生提升”,这种说法并不完全精确。在引擎词法分析阶段,let 与 const 同样会被记录在当前作用域环境中,但引擎不会为其初始化任何默认值。从代码块开始到正式声明该变量之间的区域被称为暂时性死区(Temporal Dead Zone, TDZ)。在死区内读取该变量会直接引发 ReferenceError,而 var 则会在声明前被隐式初始化为 undefined。
3. 常见易混淆点:const 声明的对象属性是否可改?
开发者常问:“既然使用了 const,为什么还能修改对象的属性?”这里的关键在于内存地址绑定与值变动的区别:
- 对于基本数据类型(如 Number、String、Boolean),变量直接存储其值,因此
const会彻底锁死该值。 - 对于引用数据类型(如 Object、Array),
const锁定的仅仅是变量指向堆内存的内存地址指针。只要不尝试对该变量执行赋值操作改变其指向,修改对象内部的属性或向数组推入新元素是完全合法的。
// const 引用不可变实操演示
const userConfig = {
theme: "dark",
version: 1
};
// 允许: 修改引用对象的属性内部数据
userConfig.version = 2;
console.log(userConfig.version); // 输出: 2
// 报错: 尝试改变变量指向的内存地址
try {
userConfig = { theme: "light", version: 1 };
} catch (error) {
console.log("捕获错误:", error.message); // 输出: Assignment to constant variable.
}
二、流程控制与迭代驱动:从传统循环到现代集合遍历
循环结构用于重复执行某段特定任务,直到满足终止条件。JavaScript 提供了多种循环控制方式,针对不同的数据结构与执行场景,选用恰当的循环能够显著提升代码的可读性与运行性能。
1. 经典计数循环:for 与 while 的执行流程
传统的 for 循环通过“初始化语句;条件判定;步长更新”三部曲工作,非常适合遍历已知长度的连续索引序列。而 while 循环则在每次进入循环体前评估单一条件表达式,常用于循环次数不确定、由外部状态转移驱动的场景。
// 1. 标准 for 循环演示
const scores = [88, 92, 79, 95, 60];
let passCount = 0;
for (let i = 0; i < scores.length; i++) {
if (scores[i] >= 80) {
passCount++;
}
}
console.log("80分以上人数:", passCount); // 输出: 3
// 2. while 循环演示
let balance = 100;
let round = 0;
while (balance > 20) {
balance -= 25;
round++;
}
console.log(`执行 ${round} 轮后剩余资金: ${balance}`); // 输出: 执行 4 轮后剩余资金: 0
2. 现代集合迭代:for...of 与 for...in 的核心选型
在处理复合数据结构时,许多开发者容易混淆 for...of 与 for...in:
for...of(ES6新增):专门用于遍历具有迭代器接口(Iterator)的集合,如Array、String、Map、Set等。它每次循环直接产出集合的具体元素值。for...in:设计初衷是用于遍历普通 JavaScript 对象的可枚举属性键名(Key)。若用其遍历数组,不仅返回的是字符串类型的数字索引,还会顺带遍历出原型链上的可枚举属性,因此严禁在生产中使用for...in遍历普通数组。
3. 集合遍历代码演示
通过以下示例,我们可以清晰地观察到 for...of 遍历数组值与 for...in 遍历对象键的实际运行效果:
// 1. for...of 遍历数组项
const products = ["鼠标", "机械键盘", "高分显示器"];
for (const item of products) {
console.log("商品名称:", item);
}
// 输出:
// 商品名称: 鼠标
// 商品名称: 机械键盘
// 商品名称: 高分显示器
// 2. for...in 遍历对象键与值
const userProfile = {
username: "alex_coder",
role: "admin",
department: "Tech"
};
for (const prop in userProfile) {
// 建议配合 hasOwnProperty 过滤原型链继承属性
if (Object.prototype.hasOwnProperty.call(userProfile, prop)) {
console.log(`属性名: ${prop}, 属性值: ${userProfile[prop]}`);
}
}
// 输出:
// 属性名: username, 属性值: alex_coder
// 属性名: role, 属性值: admin
// 属性名: department, 属性值: Tech
三、函数封装与执行抽象:声明、表达式与箭头函数
函数是 JavaScript 中封装计算逻辑、组织业务流程和实现代码复用的核心单元。在 JavaScript 中,函数是一等公民(First-Class Citizens),能够作为参数传递、作为返回值输出,或赋值给变量。
1. 函数声明与函数表达式的加载差异
函数声明(Function Declaration)享有完全的提升特权:在脚本解析时,函数体本身会被提升至所在作用域的顶部,因此在物理书写上,调用语句完全可以放在声明语句之前。而函数表达式(Function Expression)本质上是变量赋值,其调用权限完全取决于变量声明与赋值的执行顺序。
// 1. 函数声明(支持前置调用)
console.log(greetDeclaration("张三")); // 输出: 你好,张三!
function greetDeclaration(name) {
return `你好,${name}!`;
}
// 2. 函数表达式(严格遵循运行时序)
// 若在下方赋值前调用 greetExpression("李四"),将引发 ReferenceError 或 TypeError
const greetExpression = function(name) {
return `欢迎回来,${name}!`;
};
console.log(greetExpression("李四")); // 输出: 欢迎回来,李四!
2. 箭头函数的语法特性与边界约束
ES6 引入的箭头函数(Arrow Function)极大地简化了函数书写,但它绝非简单的语法糖,在底层语义上有明确的边界:
- 无独立 this 绑定:箭头函数内部没有自己的
this,其引用的this严格继承自外层词法环境(Lexical Scope)。 - 无 arguments 对象:箭头函数内部无法访问传统的
arguments伪数组,若需获取全部传参,应统一使用 ES6 剩余参数(Rest Parameters)。 - 无法作为构造函数:箭头函数没有
prototype原型属性,不能通过new关键字实例化。
3. 默认参数与剩余参数实例
// 1. 默认参数应用
const calculateTotal = (price, taxRate = 0.08, discount = 0) => {
return price * (1 + taxRate) - discount;
};
console.log("最终计费:", calculateTotal(100)); // 输出: 108 (采用默认税率 0.08)
// 2. 剩余参数 (...rest) 应用
const aggregateLogs = (level, ...messages) => {
const timestamp = "2026-10-26";
// messages 此时是一个标准数组,支持一切数组方法
return `[${timestamp}] [${level}] ` + messages.join(" | ");
};
console.log(aggregateLogs("INFO", "用户登录", "IP: 192.168.1.1", "设备: 移动端"));
// 输出: [2026-10-26] [INFO] 用户登录 | IP: 192.168.1.1 | 设备: 移动端
四、综合实战演练:变量、循环与函数的协同应用
在实际工程开发中,变量、循环与函数从不孤立存在。变量承担状态保持与边界控制,循环驱动数据流转与集合过滤,函数则将具体的业务算法隔离并模块化。下面通过一个完整的电商订单分析场景,展示三者的协同协作模式。
1. 完整实战代码演示:订单过滤与营收统计分析器
/**
* 业务场景:电商订单统计处理器
* 功能要求:
* 1. 过滤已取消(cancelled)的无效订单
* 2. 针对有效订单,计算含税总额(单价 * 数量 * (1 + 税率))
* 3. 统计有效订单总营收与高客单价订单列表
*/
// 1. 数据模型准备(变量层)
const orderList = [
{ id: "ORD-101", title: "降噪无线耳机", price: 299, count: 2, status: "paid" },
{ id: "ORD-102", title: "人体工学电脑椅", price: 1200, count: 1, status: "cancelled" },
{ id: "ORD-103", title: "4K 便携显示器", price: 1850, count: 1, status: "paid" },
{ id: "ORD-104", title: "机械键盘轴体包", price: 89, count: 3, status: "paid" },
{ id: "ORD-105", title: "雷电4数据线", price: 159, count: 2, status: "pending" }
];
// 2. 核心计算函数(函数层:纯函数封装)
const computeItemCost = (unitPrice, quantity, taxRate = 0.06) => {
return unitPrice * quantity * (1 + taxRate);
};
const formatPrice = (amount) => {
return `¥${amount.toFixed(2)}`;
};
// 3. 流程处理与汇总驱动(协同控制层)
function analyzeOrders(orders, highValueThreshold = 500) {
// 局部状态变量定义
let totalRevenue = 0;
let processedCount = 0;
const highValueOrders = [];
// 循环层:采用 for...of 遍历数据集合
for (const order of orders) {
// 流程控制:遇到已取消订单立即跳过本次循环
if (order.status === "cancelled") {
continue;
}
// 调用计算函数,处理单笔订单金额
const orderCost = computeItemCost(order.price, order.count);
totalRevenue += orderCost;
processedCount++;
// 条件分支:筛选高客单价订单
if (orderCost > highValueThreshold) {
highValueOrders.push({
id: order.id,
title: order.title,
finalCost: formatPrice(orderCost)
});
}
}
// 返回最终结构化分析指标
return {
totalRevenue: formatPrice(totalRevenue),
processedCount,
highValueOrders
};
}
// 4. 执行统计并打印测试输出
const report = analyzeOrders(orderList, 500);
console.log("----- 订单结算综合报告 -----");
console.log("有效结算订单数:", report.processedCount);
console.log("有效订单总流水:", report.totalRevenue);
console.log("高客单价订单明细:", JSON.stringify(report.highValueOrders, null, 2));
2. 运行结果控制台输出示例
----- 订单结算综合报告 -----
有效结算订单数: 4
有效订单总流水: ¥3178.94
高客单价订单明细: [
{
"id": "ORD-101",
"title": "降噪无线耳机",
"finalCost": "¥633.88"
},
{
"id": "ORD-103",
"title": "4K 便携显示器",
"finalCost": "¥1961.00"
}
]
3. 核心注意事项与代码防坑建议
- 变量声明首选
const:日常编码时,建议 90% 以上的变量默认声明为const,只有在明确需要重新赋值(如循环累加器、步长计数器)时才切换为let,彻底杜绝var的使用。 - 警惕死循环(Infinite Loop):编写
while或带条件的for循环时,务必确认循环体内部具备改变终止条件的推进语句,避免导致主线程堵塞与浏览器无响应崩溃。 - 保持函数职责单一:函数内部应当专注于单一任务的实现,如金额计算函数只负责数值计算,不直接操作外部 DOM 或直接篡改输入参数,从而保持逻辑的纯粹性与高可测性。
五、总结
掌握 JavaScript 的核心基础语法,关键在于建立清晰的思维模型:变量为程序确定数据边界与生命周期,循环为数据集提供高效的线性流动,而函数则将抽象规则沉淀为稳定可靠的复用组件。在现代前端工程体系下,坚持规范化使用 const/let、优先采用更语义化的 for...of 迭代,并合理搭配纯函数与箭头函数,是编写出健壮、优雅且易维护代码的坚实起点。
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
相关标签:








