javascript作用域链与执行环境详解
发布时间 - 2026-01-11 00:22:13 点击率:次前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

作用域、作用域链、执行环境、执行环境栈以及this的概念在javascript中非常重要,本人经常弄混淆,这里梳理一下;
- 局部作用域函数内部的区域,全局作用域就是window;
- 作用域链取决于函数被声明时的位置,解析标识符的时候就先找当前作用域,再向外查找,直到全局,这样一个顺序;和函数在哪里调用无关;
- 执行环境就是函数可访问的数据和变量的集合,也就是函数的作用域链上的所有数据和变量;
- 执行环境栈就是根据代码执行顺序,各执行环境按照栈的形式逐层访问,并且用完了退出来扔掉;如果当前执行环境(存放当前作用域链里的数据和变量)找不到变量,那就是找不到了,不会往之前的那个执行环境查找,它和作用域链是不同的;
- this是一个对象,它取决于是谁执行的,谁执行那就是谁;(this的概念还是不太清楚,这里写的有点万金油,过两天再来修正)
作用域
JavaScript没有块级作用域的概念,只有函数级作用域:变量在声明它们的函数体及其子函数内是可见的。
作用域就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期,在JavaScript中变量的作用域有全局作用域和局部作用域。
变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局作用域;
<script type="text/javascript">
function test1(){
a = 1;//全局变量,只有在当前函数运行时,才有效
}
test1();
console.log(a);//1 注意test1函数必须运行,不然找不到a
</script>
全局变量可以当做window对象的属性用,他们是一样的;
<script type="text/javascript"> var b = 1;//全局变量 console.log(b === window.b);//true 全局变量可以当做window对象的属性用,他们是一样的; </script>
window对象的所有属性拥有全局作用域,在代码任何地方都可以访问;
函数内部声明的变量就是局部变量,只能在函数体内使用,函数的参数虽然没有使用var但仍然是局部变量。
<script type="text/javascript">
var c = 1;//全局变量
// console.log(d);//ReferenceError: d is not defined 引用错误,当前作用域就是最外层作用域,依然找不到d
function test2(d){
console.log(c);//1 全局变量,哪都可以访问;(先找当前作用域,找不到,就向外层作用域找,直到window最外层,找到了)
console.log(d);//3 形参是局部变量,只有当前作用域下可以访问
}
test2(3);
</script>
作用域链
作用域链取决于函数被声明时的位置,解析标识符的时候就先从当前作用域开始找,在当前作用域中无法找到时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(也就是全局作用域)为止;它的路线已经被定死了,和函数在哪里运行无关;
<script type="text/javascript">
var a = 1;
var b = 2;
var c = 3;
var d = 4;
function inner(d) {//它的作用域链是inner---全局
var c = 8;
console.log(a);//1 当前作用域找不到a,去全局作用域找到了a=1
console.log(b);//2 当前作用域找不到b,去全局作用域找到了b=2
console.log(c);//8 当前作用域找到了c=8
console.log(d);//7 当前作用域找到了d=7,形参也是局部作用域
// console.log(e);//ReferenceError: e is not defined 引用错误,找不到e, 它的作用域链是inner---全局
console.log(a+b+c+d);//18
}
function outter(e) {
var a = 5;//inner()的作用域链是inner---全局,所以这个a相当于无效
var b = 6;//inner()的作用域链是inner---全局,所以这个a相当于无效
inner(7);
}
outter(999);//这个999无效,里面的e根本找不到
</script>
在多层的嵌套作用域中可以定义同名的标识符,这叫作“遮蔽效应”,内部的标识符“遮蔽”了外部的标识符
通过window.a这种技术可以访问那些被同名变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无论如何都无法被访问到;
<script type="text/javascript">
var a = 'Lily';
var b = 'Lucy';
function outer() {
var b = 'Jesica';
var c = 'Susan';
function inner(c) {
console.log(a);//Lily
console.log(window.b);//Lucy
console.log(b);//Jesica
console.log(c);//Jenifer
}
inner('Jenifer');
}
outer();
</script>
执行环境
执行环境(execution context),也叫执行上下文。每个执行环境都有一个变量对象(variable object),保存函数可访问的所有变量和数据(也就是函数的作用域链上的所有数据和变量)。我们的代码访问不到它,它是给引擎使用的;
执行环境栈,当执行进入一个函数时,函数的执行环境就会被推入一个栈中。而在函数执行完之后,栈将其执行环境移除,它里面的变量和数据会被标记清除,等待垃圾回收,再把控制权返回给之前的执行环境。javascript程序中的执行正是由这个机制控制着;
需要注意的是如果当前执行环境(存放当前作用域链里的数据和变量)找不到变量,那就是找不到了,不会往之前的那个执行环境查找,和作用域链是不一样的;
代码的执行顺序也不全是一行一行的执行,而是和函数的调用顺序有关:
- 代码进入全局执行环境,全局执行环境放入环境栈;
- 当执行到一个函数时,就把这个函数的执行环境推入到环境栈顶端,之前的执行环境往后;
- 全局执行环境最先进入,所以一直在底端;就和栈的概念差不多;
- 函数执行完之后,再把它的执行环境从作用域链顶端移除,它保存的数据和函数都被标记清除,等待垃圾回收;
- 控制权交给之前的执行环境,继续往下执行;
- 当页面关闭时,全局执行环境才销毁;
<script type="text/javascript">
var a = 1;
var b = 2;
var c = 3;
var d = 4;
function inner(d) {//它的作用域链是inner---全局
var c = 8;
console.log(a);//1 当前作用域找不到a,去全局作用域找到了a=1
console.log(b);//2 当前作用域找不到b,去全局作用域找到了b=2
console.log(c);//8 当前作用域找到了c=8
console.log(d);//7 当前作用域找到了d=7,形参也是局部作用域
// console.log(e);//ReferenceError: e is not defined 引用错误,找不到e, 它的作用域链是inner---全局
console.log(a+b+c+d);//18
}
function outter(e) {
var a = 5;//inner()的作用域链是inner---全局,所以这个a相当于无效
var b = 6;//inner()的作用域链是inner---全局,所以这个a相当于无效
inner(7);
}
outter(999);//这个999无效,里面的e根本找不到
</script>
以上代码的执行顺序:
代码执行进入全局执行环境,并对全局执行环境中的代码进入声明提升;
执行第2行,赋值a=1; 然后第3行赋值b=2; 然后第4行赋值c=3; 然后第5行赋值d=4;
执行第20行,调用outer(999)函数,然后进入outer(999)函数执行环境,声明提升,并将实参999传给形参e;现在环境栈中有两个执行环境,outer(999)是当前执行环境;
执行第16行,赋值a=5; 然后第17行赋值b=6;
执行第18行,调用inner(7)函数,然后进入inner(7)函数执行环境,声明提升,并将实参7传给形参d;
执行第7行,赋值c=8; 然后运算并输出;
代码优化
由于在作用域链上查找变量是需要消耗性能的,我们应该尽快的找到变量,所以在函数多层嵌套的时候,我们应尽可能的使用函数内部的局部变量;
我们在函数内部使用全局变量可以说是一种跨作用域操作,如果某个跨作用域的值在函数的内部被多次使用,那么我们就把它存储到局部变量里,这样可以提高性能。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# js
# 作用域链
# 执行环境
# JavaScript执行环境及作用域链实例分析
# javascript基础进阶_深入剖析执行环境及作用域链
# 浅谈javascript中执行环境(作用域)与作用域链
# 深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解
# js 函数的执行环境和作用域链的深入解析
# JavaScript中的执行环境和作用域链
# 找不到
# 找到了
# 全局变量
# 并将
# 最外层
# 再把
# 移除
# 先找
# 自己的
# 的是
# 是一个
# 这是
# 那就是
# 一个函数
# 就会
# 都有
# 是一种
# 我会
# 那就
# 不太
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何快速使用云服务器搭建个人网站?
HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】
企业网站制作这些问题要关注
Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
Android okhttputils现在进度显示实例代码
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
北京专业网站制作设计师招聘,北京白云观官方网站?
Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转
Laravel如何实现API资源集合?(Resource Collection教程)
Laravel如何优化应用性能?(缓存和优化命令)
如何快速搭建高效简练网站?
php做exe能调用系统命令吗_执行cmd指令实现方式【详解】
如何为不同团队 ID 动态生成多个非值班状态按钮
Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置
如何在阿里云域名上完成建站全流程?
济南网站建设制作公司,室内设计网站一般都有哪些功能?
Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
浅谈Javascript中的Label语句
Laravel如何实现用户密码重置功能?(完整流程代码)
国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?
ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法
JavaScript如何实现音频处理_Web Audio API如何工作?
哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?
如何实现javascript表单验证_正则表达式有哪些实用技巧
怎么用AI帮你设计一套个性化的手机App图标?
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
如何撰写建站申请书?关键要点有哪些?
昵图网官网入口 昵图网素材平台官方入口
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】
Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出
如何在企业微信快速生成手机电脑官网?
网站制作企业,网站的banner和导航栏是指什么?
佛山网站制作系统,佛山企业变更地址网上办理步骤?
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
Python制作简易注册登录系统
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧
Linux网络带宽限制_tc配置实践解析【教程】
如何快速生成ASP一键建站模板并优化安全性?
如何基于云服务器快速搭建网站及云盘系统?
JavaScript如何实现错误处理_try...catch如何捕获异常?
详解jQuery停止动画——stop()方法的使用
如何在服务器上三步完成建站并提升流量?
什么是javascript作用域_全局和局部作用域有什么区别?
高端建站三要素:定制模板、企业官网与响应式设计优化
Linux后台任务运行方法_nohup与&使用技巧【技巧】
Laravel如何使用.env文件管理环境变量?(最佳实践)

