
在蓝桥杯 Web 应用开发赛道中,变量声明的特性与 DOM 事件绑定是核心高频考点。本文将结合实战代码,深度解析var、let、const的区别,以及两种事件绑定方案的原理,并对应蓝桥杯考点进行拓展。
一、变量声明:var、let、const 的核心特性
1.1 预解析(变量提升)
核心区别:
-
var存在变量提升:声明会被提升到作用域顶部,但赋值仍在原地。 -
let/const不存在变量提升:声明前使用会触发 "暂时性死区"(ReferenceError)。
代码实例:
// var 的变量提升
console.log(a, b, c); // 输出:undefined undefined undefined(变量已声明,未赋值)
var a = 'ggx handsome';
var b = 1;
var c = 10;
// let/const 的暂时性死区
// console.log(const1); // 报错:ReferenceError(const1 未初始化)
const const1 = 10;
console.log(const1); // 输出:10
考点汇总表:
|-----|----------|---------------|
| 特性 | var | let/const |
| 预解析 | ✅ 存在变量提升 | ❌ 不存在(暂时性死区) |
1.2 块级作用域
核心区别:
-
var无块级作用域:作用域为函数级 或全局 ,{}无法限制其范围。 -
let/const有块级作用域:仅在{}内有效,可隔离变量。
代码实例:
// let 的块级作用域
let a = 10;
console.log(a); // 输出:10(全局作用域)
if (1 > 0) {
let a = 20;
console.log(a); // 输出:20(块级作用域)
}
console.log(a); // 输出:10(全局作用域不受块级影响)
// for 循环中的 let(蓝桥杯高频场景)
for (let i = 0; i < 5; i++) {
console.log(i); // 输出:0 1 2 3 4(i 仅在循环内有效)
}
// console.log(i); // 报错:i 未定义(块级作用域隔离)
考点汇总表:
|-------|--------------|---------------|
| 特性 | var | let/const |
| 块级作用域 | ❌ 无(函数 / 全局) | ✅ 有({} 内有效) |
1.3 const 的常量特性
const 用于定义常量,核心规则:
-
声明时必须赋值(否则报错);
-
基本数据类型(如数字、字符串)不可修改;
-
引用数据类型(如数组、对象)地址不可改,但内部属性 / 元素可修改。
代码实例:
// 1. 声明时必须赋值
// const const2; // 报错:Missing initializer in const declaration
const const2 = 'ggx handsome';
// 2. 基本类型不可修改
// const2 = 'ggx really handsome'; // 报错:Assignment to constant variable
// 3. 引用类型:地址不可改,属性/元素可改
const array1 = [1, 2, 3, 4, 5];
const array2 = [1, 2, 3, 4, 5];
console.log(array1 == array2); // 输出:false(地址不同)
array1[0] = 'ggx'; // 修改元素(地址不变)
console.log(array1); // 输出:['ggx', 2, 3, 4, 5]
const obj1 = { name: 'ggx' };
obj1.name = 'ggxC'; // 修改属性(地址不变)
console.log(obj1); // 输出:{ name: 'ggxC' }
考点汇总表:
|----------|-----------------------|
| const 特性 | 规则说明 |
| 声明赋值 | ✅ 必须赋值,否则报错 |
| 基本类型 | ❌ 不可修改值 |
| 引用类型 | ❌ 不可修改地址,✅ 可修改属性 / 元素 |
二、事件绑定的两种方案与蓝桥杯闭包考点
在蓝桥杯 DOM 操作题中,"循环绑定点击事件,获取正确索引" 是经典闭包考点。以下结合代码解析两种方案:
2.1 方案一:var + 自定义属性(ES5 兼容方案)
问题 :var 无块级作用域,循环内的 i 是共享变量 ,循环结束后 i 为最大值(如 5),点击时直接用 i 会出错。
解决 :通过 setAttribute 给每个元素存储索引,点击时用 this.getAttribute('index') 获取。
代码实例:
var names = document.querySelectorAll('.name');
var lastIndex = 0;
for (var i = 0; i < names.length; i++) {
var div = names[i];
div.setAttribute('index', i); // 存储索引到自定义属性
div.onclick = function() {
var index = this.getAttribute('index'); // 获取当前元素的索引
names[lastIndex].className = 'name'; // 清除上一个高亮
names[index].className = 'name highLight'; // 当前元素高亮
lastIndex = index;
console.log(i); // 点击任意元素,输出:5(var 的共享特性)
};
}
2.2 方案二:let + 块级作用域(ES6 推荐方案)
优势 :let 有块级作用域,每次循环的 i 都是独立变量 ,事件绑定可直接使用 i,无需额外操作 DOM。
代码实例:
var names = document.querySelectorAll('.name');
var lastI = 0;
for (let i = 0; i < names.length; i++) {
names[i].onclick = () => {
console.log(i); // 点击对应元素,输出:0、1、2...(let 的块级绑定)
names[lastI].classList.remove('highLight'); // 清除上一个高亮
names[i].classList.add('highLight'); // 当前元素高亮
lastI = i;
};
}
2.3 蓝桥杯考点:闭包与作用域辨析
考点逻辑:
-
var方案:i是全局变量,点击事件触发时才读取i(此时i已为循环结束值),需通过自定义属性 "保存" 索引。 -
let方案:每次循环生成独立的块级作用域,i被绑定在当前作用域,点击时直接读取作用域内的i,天然解决闭包问题。
考法示例:
-
给出
var循环绑定事件的代码,问点击后输出什么(答案:循环结束值); -
要求修复索引错误(方案:改用
let,或用闭包 / 自定义属性)。
三、知识点终极汇总表
3.1 var、let、const 全面对比
|-------|--------------|-------------|---------------------|
| 特性 | var | let | const |
| 预解析 | ✅ 存在变量提升 | ❌ 暂时性死区 | ❌ 暂时性死区 |
| 块级作用域 | ❌ 无(函数 / 全局) | ✅ 有({} 内有效) | ✅ 有({} 内有效) |
| 重新赋值 | ✅ 可以 | ✅ 可以 | ❌ 基本类型不可改,引用类型地址不可改 |
| 声明时赋值 | ✅ 可以不赋值 | ✅ 可以不赋值 | ❌ 必须赋值 |
| 重复声明 | ✅ 同一作用域可重复 | ❌ 同一作用域不可 | ❌ 同一作用域不可 |
3.2 两种事件绑定方案对比
|-----|---------|-----------|-----------|-------|
| 方案 | 变量声明 | 解决方式 | 蓝桥杯适配性 | 代码简洁度 |
| 方案一 | var | 自定义属性存储索引 | ✅ 兼容 ES5 | ⭐⭐ |
| 方案二 | let | 块级作用域绑定索引 | ✅ 推荐(ES6) | ⭐⭐⭐⭐⭐ |
蓝桥杯备考建议:
-
优先用
let/const替代var,避免作用域陷阱; -
循环绑定事件时,
let是最简洁的解决方案; -
若需兼容 ES5,再考虑自定义属性或闭包。