大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript
等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter
等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js
进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。
技术qq交流群:906392632
大家好,我是小杨,一个和JS相爱相杀6年的前端工程师。今天我要带大家揭开JavaScript代码执行的神秘面纱,保证让你看完后恍然大悟:"原来我的代码是这样跑的!"
一、执行上下文:代码的"舞台"
想象一下,JS引擎就像个剧场,每次函数调用就像一场新的演出。而执行上下文就是这个演出的"舞台",决定了哪些"演员"(变量和函数)可以上场。
先看个简单例子:
javascript
function sayHello() {
let me = '小杨';
console.log(`大家好,我是${me}`);
}
sayHello();
当调用sayHello()
时,JS就会创建一个新的执行上下文。
二、执行上下文的"人生三阶段"
每个执行上下文都会经历三个阶段:
-
创建阶段:准备舞台
- 创建变量对象(VO)
- 建立作用域链
- 确定this指向
-
执行阶段:正式演出
- 变量赋值
- 函数调用
- 执行代码
-
销毁阶段:演出结束
- 出栈等待垃圾回收
三、变量提升的真相
来看个经典例子:
javascript
console.log(me); // undefined
var me = '小杨';
console.log(me); // '小杨'
为什么不会报错?因为在创建阶段,变量声明会被提升,但赋值不会。
小杨踩坑记:
javascript
function test() {
console.log(me); // undefined
if(false) {
var me = '小杨';
}
}
test();
即使if条件为false,变量声明依然会被提升!
四、作用域链:变量的"寻亲记"
javascript
let name = '全局小杨';
function outer() {
let name = '外层小杨';
function inner() {
console.log(name); // '外层小杨'
}
inner();
}
outer();
JS会沿着作用域链一层层往上找变量,就像寻亲一样。
五、this指向:最难捉摸的"演员"
this的指向总让人头大,记住几个规则:
- 普通函数调用:this指向window(严格模式undefined)
- 方法调用:this指向调用对象
- new调用:this指向新创建的对象
javascript
let obj = {
me: '小杨',
say: function() {
console.log(this.me);
}
};
obj.say(); // '小杨'
let fn = obj.say;
fn(); // undefined (this指向window)
六、闭包:执行上下文的"遗产"
javascript
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
let counter = createCounter();
counter(); // 1
counter(); // 2
即使createCounter的执行上下文已经销毁,内部函数依然能访问count变量,这就是闭包的魔力。
七、实战应用:避免常见坑
- 避免变量污染:
javascript
// 错误做法
for(var i=0; i<5; i++) {
setTimeout(() => {
console.log(i); // 全是5
}, 100);
}
// 正确做法
for(let i=0; i<5; i++) {
setTimeout(() => {
console.log(i); // 0,1,2,3,4
}, 100);
}
- 合理使用闭包:
javascript
// 缓存计算结果
function createCache() {
let cache = {};
return function(key, value) {
if(value !== undefined) {
cache[key] = value;
}
return cache[key];
}
}
八、总结
- 执行上下文是JS代码执行的环境
- 变量提升和作用域链是理解JS的关键
- this指向需要根据调用方式判断
- 闭包可以让函数"继承"执行上下文的变量
最后留个思考题:
javascript
let obj = {
me: '小杨',
say: () => {
console.log(this.me);
}
};
obj.say(); // 输出什么?为什么?
欢迎在评论区讨论你的答案!下期我会详细讲解箭头函数的this指向问题。