JavaScript关于作用域、作用域链和闭包的理解

JavaScript关于作用域、作用域链和闭包的理解作用域先来谈谈变量的作用域变量的作用域无非就是两种 全局变量和局部变量 全局作用域 最外层函数定义的变量拥有全局作用域 即对任何内部函数来说 都是可以访问的 scriptvarout outer functionfn console log outerVar fn res

作用域

<script> var outerVar = "outer"; function fn(){ 
     console.log(outerVar); } fn();//result:outer  
   script>
<script> function fn(){ 
     var innerVar = "inner"; } fn(); console.log(innerVar);// ReferenceError: innerVar is not defined  
   script>

需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

 <script> function fn(){ 
     innerVar = "inner"; } fn(); console.log(innerVar);// result:inner  
   script>

再来看一个代码:

 <script> var scope = "global"; function fn(){ 
     console.log(scope);//result:undefined var scope = "local"; console.log(scope);//result:local; } fn();  
   script>

很有趣吧,第一个输出居然是undefined,原本以为它会访问外部的全局变量(scope=”global”),但是并没有。这可以算是javascript的一个特点,只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提前声明”

 <script> var scope = "global"; function fn(){ 
     var scope;//提前声明了局部变量 console.log(scope);//result:undefined scope = "local"; console.log(scope);//result:local; } fn();  
   script>
for(int i = 0; i < 10; i++){ //i的作用范围只在这个for循环 } printf("%d",&i);//error

但是javascript不同,并没有所谓的块级作用域,javascript的作用域是相对函数而言的,可以称为函数作用域:

 <script> for(var i = 1; i < 10; i++){ //coding } console.log(i); //10   
   script>

作用域链(Scope Chain)

执行环境(execution context)

每个函数运行时都会产生一个执行环境,而这个执行环境怎么表示呢?js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。
全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。
js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。
举个例子:






 <script> var scope = "global"; function fn1(){ 
     return scope; } function fn2(){ 
     return scope; } fn1(); fn2();  
   script>

标识符解析是沿着作用域链一级一级地搜索标识符地过程。搜索过程始终从作用域链地前端开始,然后逐级向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)—-《JavaScript高级程序设计》

 <script> function outer(){ 
     var scope = "outer"; function inner(){ 
     return scope; } return inner; } var fn = outer(); fn();  
   script>

像上面这种内部函数的作用域链仍然保持着对父函数活动对象的引用,就是闭包(closure)

闭包

 <script> function outer(){ 
     var result = new Array(); for(var i = 0; i < 2; i++){ 
   //注:i是outer()的局部变量 result[i] = function(){ 
     return i; } } return result;//返回一个函数对象数组 //这个时候会初始化result.length个关于内部函数的作用域链 } var fn = outer(); console.log(fn[0]());//result:2 console.log(fn[1]());//result:2  
   script>
 <script> function outer(){ 
     var result = new Array(); for(var i = 0; i < 2; i++){ //定义一个带参函数 function arg(num){ 
     return num; } //把i当成参数传进去 result[i] = arg(i); } return result; } var fn = outer(); console.log(fn[0]);//result:0 console.log(fn[1]);//result:1  
   script>
 <script> function outer(){ 
     var result = new Array(); for(var i = 0; i < 2; i++){ //定义一个带参函数 function arg(num){ 
     function innerarg(){ 
     return num; } return innerarg; } //把i当成参数传进去 result[i] = arg(i); } return result; } var fn = outer(); console.log(fn[0]()); console.log(fn[1]());  
   script>
 function outer(){ 
    var result = new Array(); for(var i = 0; i < 2; i++){ //定义一个带参函数 result[i] = function(num){ 
    function innerarg(){ 
    return num; } return innerarg; }(i);//预先执行函数写法 //把i当成参数传进去 } return result; }

关于this对象

关于闭包经常会看到这么一道题:

  var name = "The Window";   var object = {     name : "My Object",     getNameFunc : function(){ 
          return function(){ 
            return this.name;       };     }   };   alert(object.getNameFunc()());//result:The Window

《javascript高级程序设计》一书给出的解释是:

this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象。不过,匿名函数具有全局性,因此this对象同常指向window


参考资料

  • Js作用域与作用域链详解
  • 阮一峰博文《学习Javascript闭包(Closure)》
  • JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
  • 结合代码图文讲解JavaScript中的作用域与作用域链
  • 《Javascript高级程序设计》
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205734.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午5:19
下一篇 2026年3月19日 下午5:20


相关推荐

  • OpenClaw最新版本差异对比与安装指南

    OpenClaw最新版本差异对比与安装指南

    2026年3月15日
    2
  • drawstring 文本居中_c#-Graphics.DrawString()的中心文本输出

    drawstring 文本居中_c#-Graphics.DrawString()的中心文本输出c Graphics DrawString 的中心文本输出我正在使用 NETCF WindowsMobil Graphics 类和 DrawString 方法将单个字符呈现到屏幕 问题是我似乎无法使其正确居中 无论我为字符串渲染的位置的 Y 坐标设置什么 它总是比该值低 并且文本大小越大 Y 偏移量就越大 例如 在文本大小 12 处 偏移量约为 4 但在 32 处 偏移量约为 10 我希望角色垂直占据绘制的

    2025年11月2日
    5
  • 微信小程序开发环境(阿里云服务搭建+可运行的demo)「建议收藏」

    最近微信小程序异常火爆,很多人在学习,下面带着大家搭建下微信小程序的调试环境(client+server),并调试一套demo源码(JavaScript和node.js基础即可,微信推荐使用的语言,无前端编程基础,去菜鸟教程简单学习下JavaScript,node.js,mysql即可),方便大家学习。微信小程序搭建环境必需的两点:云服务器,域名,下面一步步给搭建演示如果在一台阿里云服…

    2022年4月16日
    120
  • java getopt_getopt使用例子

    java getopt_getopt使用例子绝大多数脚本使用 getopts 应该就可以满足需求了 如果需要支持长选项以及可选参数 那么就需要使用 getopt 了 getopt 和 getopts 类似 也是通过冒号来区分选项是否接受参数值 其定义如下 后面没有冒号 表示选项不接参数后面有一个冒号 表示选项必须接参数后面有两个冒号 表示选项参数可选我们来看一下这个命令 example sh a bvalue2argv3 我们看到这

    2026年3月18日
    2
  • 【python】lambda表达式与排序

    【python】lambda表达式与排序lambda表达式简单易用的匿名函数文章目录lambda表达式1.什么是lambda表达式2.lambda表达式语法3.lambda表达式的主要用途3.1list.sort()函数3.2自定义属性排序3.3常见的小问题3.4二维列表的排序1.什么是lambda表达式在学习lambda表达式之前,我们先写一个求圆的面积的函数defget_area(radius):return3.14*radius**2radius=float(input())pri

    2022年10月17日
    4
  • MiniMax上线MaxClaw抢占AI助手赛道制高点

    MiniMax上线MaxClaw抢占AI助手赛道制高点

    2026年3月14日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号