一、变量声明的进化史:var → let → const
1.1 var 的"怪异"特性
javascript
// 变量提升示例
console.log(a); // undefined
var a = 1;
// 全局绑定陷阱
var name = "全局变量";
function showName() {
console.log(name);
var name = "局部变量";
}
showName(); // 输出undefined(变量提升导致局部name覆盖全局)
/*
等价于
function showName() {
var name;
console.log(name);
// 输出undefined
name = "局部变量";
}
*/
1.2 块级作用域革命
javascript
// TDZ(暂时性死区)演示
if (true) {
console.log(tmp); // ReferenceError
let tmp = "存在性证明";
}
1.3 常量的真谛
javascript
// const并非不可变
const obj = { name: "不变的引用" };
obj.age = 25; // 合法操作
二、作用域链与执行上下文
2.1 执行阶段的秘密
javascript
// 编译阶段:函数优先提升
foo(); // 正常执行
var foo = function () {}; // 表达式不会完全提升
function foo() {
console.log("函数声明");
}
2.2 闭包的高级应用
javascript
// 私有变量模式
function Counter() {
let count = 0;
return {
increment: () => ++count,
getCount: () => count,
};
}
三、this 的七十二变
3.1 四种调用方式大对比
javascript
const user = {
name: "Alice",
greet: () => {
console.log(this.name); // 箭头函数继承外层this
setTimeout(() => {
console.log(this.name); // 双重继承
}, 100);
},
};
user.greet(); // 始终指向外层作用域
3.2 严格模式下的 this 革命
javascript
// 非严格模式
function foo() {
console.log(this);
}
foo(); // window
// 严格模式
function bar() {
"use strict";
console.log(this);
}
bar(); // undefined
// 对象方法调用示例
var a = {
name: "lou boss",
fn: function () {
console.log(this); // Object { name: "lou boss" }
console.log(this.name); // lou boss
},
};
a.fn(); // 方法调用,this指向对象
var b = a.fn;
b(); // 严格模式下输出undefined,非严格模式指向window
四、事件循环中的 this 陷阱
javascript
// DOM事件中的this魔法
document.getElementById("btn").addEventListener("click", function () {
console.log(this.id); // 自动绑定为事件目标
});
五、最佳实践指南针
5.1 变量声明守则
- 优先使用 const,次选 let,避免 var
- 对象/数组用 const 保持引用稳定
- 循环计数器用 let 保证块级作用域
5.2 this 使用黄金法则
- 箭头函数用于保持 this 一致性
- 事件处理用 function(){}自动绑定 DOM
- 使用 bind()显式绑定上下文
- 类方法优先使用箭头函数绑定 this
5.3 严格模式迁移指南
- 添加
"use strict"
到文件顶部 - 替换所有 var 为 let/const
- 修复因 this 绑定变化导致的错误
- 利用 ESLint 进行代码规范检查
六、常见误区急救室
6.1 const 不是绝对常量
javascript
const arr = [1, 2];
arr.push(3); // 合法操作
arr = []; // 报错:Assignment to constant variable.
6.2 箭头函数的局限性
javascript
// 不能作为构造函数
const Person = () => {};
new Person(); // TypeError
// 不能绑定arguments对象
const foo = () => console.log(arguments);
foo(1, 2, 3); // ReferenceError
七、性能优化技巧
- 避免在循环中使用 var 造成闭包内存泄漏
- 用 const 代替 var 减少作用域链查找
- 合理使用箭头函数减少 bind()调用
- 利用块级作用域优化内存管理
八、未来趋势展望
随着 ESNext 的持续演进:
Temporal.deadline()
带来的异步作用域新挑战using
关键字的资源管理新范式- 模块作用域的进一步强化
结语:JavaScript 的作用域和 this 机制看似简单,实则蕴含着语言设计的深层哲学。掌握这些核心概念,不仅能解决 90%的常见 bug,更是迈向高级开发者的重要里程碑。建议读者在 Chrome 开发者工具中逐行调试每个示例,观察执行上下文的变化过程。
思考题:当箭头函数遇到 with 语句时,this 的绑定会发生什么特殊现象?欢迎在评论区分享你的探索结果。