`

JavaScript的执行环境和作用域(基础知识)

 
阅读更多

什么是JS执行环境?

        简单的来说就是变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们无法编写的代码无法访问这个对象,但是解析器在处理数据时会在后台中使用它。

        全局执行环境是最外围的一个执行环境。根据Js实现所在的宿主环境不同,表示执行环境的对象也不一样。在Web浏览器中,全局执行环境被认为是Window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或者浏览器时才会被销毁)。

      每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入到一个环境栈中。而函数在执行之后,栈将其环境弹出,把控制权返回给之前的的执行环境。Js程序中的执行流正是由这个方便的机制控制着。

      当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的作用:保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前段,始终都是当前执行的代码所在环境的变量对象。如果这个环境是个函数,则将其活动对象作为变量对象。活动对象在最开始的时候只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

       标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域的前段开始,然后依次向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)。

      例如:

      var color = "blue" ;

      function  changeColor(){

         if  ( color  ==  "blue" ){

               color = "red" ;

          }  else {

              color = "blue";

         }

     }

     changeColor();

    alert("Color is now " + color);

        在这个简单的函数中,函数changeColor()的作用域链中包含两个对象:它自己的变量对象(其中定义这个arguments对象)和全局环境的变量对象。可以在函数的内部访问变量color,就是因为可以作用域链中找到它。

       此外,在局部作用域中的变量可以在局部环境中与全局变量互换使用,如下面示例:

    var color = "blue" ;

    function  changeColor(){

         var anotherColor = "red" ;

         function swapColors(){

             var tempColor = anotherColor;

             anotherColor = color;

             color = tempColor;

            //这里可以访问color,anotherColor和tempColor

         }

           //这里可以访问color,anotherColor但是不能访问tempColor

     }

            //这里只能访问color

     changeColor();

     以上代码共涉及3个执行环境:全局环境,changeColor()的局部环境和swapColors()的局部环境。

     执行环境请看如下图:

 

        以上矩形表示特定的执行环境。其中,内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境的中的任何变量和函数。这些环境质质检的联系是线性、有次序的。每个环境都可以向上收索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个直行环境。

  

二、作用域的延长

        执行环境只有两种------全局和局部(函数),但是还是有其他方法来延长作用域链,就是一些语句可以在作用域链的前段临时增加一个变量对象,该变量对象会在代码执行完之后被移除。在两种情况会发生这种现象。具体来说,就是当执行流进入下列任何一个语句时,作用域链的前段都会增加一个变量对象:

       try-catch语句的catch块;

       with语句;

       对于with语句会将指定的对象增加到作用域链中,而对于catch语句来说,会创建一个新的变量对象,其中可能包含被抛出的错误对象的声明。

      function Url(){

          var oldUrl = "?debug=true";

          with (location){

              var  newUrl = href + oldUrl;

          }

          return newUrl;

      }

       在此,with语句接收的是location对象,因此其变量对象中就包含location对象的所有属性和方法,这个变量对象就被添加到作用域的前端。Url()函数定义了一个变量oldUrl,当在with语句中引用变量href时(实际引用的是location.href),可以在当前执行环境的变量对象中找到。当引用oldUrl时,引用的则是在Url中定义的那个变量,而该变量位于函数环境的变量对象中。至于with语句的内部,则定义了一个名为newUrl的变量,因此newUrl就成了函数执行环境的一部分,所以可以作为函数的值被返回。

 

三、没有块级作用域

      JS中没有块级作用域,不像C语言中,由花括号封闭的代码块都有自己的作用域。例如,下面代码在JS中并不会得到想象中的结果:

      if (true) { 

          var color = "blue";

      }

     alert(color);   

        这里在if语句中定义了一个变量color,如果是C、C++、JAVA中,color会在if语句中执行完毕后被销毁,但是在JS中,if语句中的变量声明会被添加到当前的执行环境(在这是全局环境)中,在使用for语句时尤其要牢记这一差异:

     for(var i = 0 ; i <10 ;i++){

         doSomething(i);

     }

     alert (i); //10

       对于有块级作用域的语言来说,for语句初始化变量的表达式所定义的变量,只会存在循环的环境中。而对于JS中来说,由for语句创建的变量即使在for循环执行结束后,也会存在于循环外部的执行环境中。

 

(1).变量声明

      使用var声明的变量会自动添加到最近的环境中。在函数内部,最近的环境就是函数的局部环境;在with语句中,最接近的环境就是函数环境,如果初始化变量时没有使用var声明,说明被动添加到全局环境。如下所示:

      function  add (num1 ,num2){

              var sum = num1 + num2 ;

              return sum;

     }

     var result = add (10,20);

    alert(sum);    //由于sum不是有效的变量,因此会导致错误

        以上代码函数add()中定义了一个局部变量sum,该变量是加法操作的结果值从函数中返回,但变量sum在函数外部是访问不到的。如果省略这个var关键字那么当add()函数执行完毕后,sum也可以访问到:  

    function  add (num1 ,num2){

              var sum = num1 + num2 ;

              return sum;

     }

     var result = add (10,20);   //30

    alert(sum);        //30

        这个例子变量sum没有使用var关键字。于是,当调用完add()函数之后,添加到全局环境中的变量sum将继续存在;即使函数已经执行完毕,后面的代码依次可以访问它。

 

(2).查询标识符

        当某个环境中为了写入或读取而引入一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程通过作用域链的前段开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到了该标识符,则搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明。

示例如下:

 

   var   color = "blue";

   function getColor(){

          return color;

   } 

   alert(getColor());   //blue

搜索流程如下:



 

 备注:小弟乃菜鸟一只,只能写一点浅层知识。如有不妥之处请多多包涵

 

 

  • 大小: 6.3 KB
分享到:
评论

相关推荐

    JavaScript基础和实例代码

    2.3.3 变量作用域 2.4 弱类型 2.5 基本数据类型 2.5.1 Number型 2.5.2 String型 2.5.3 Boolean型 2.5.4 Undefined型 2.5.5 Null型 2.5.6 Function型 2.6 组合类型 2.6.1 Array型 2.6.2 Object型 2.7 运算符 2.7.1 ...

    JavaScript每天必学之基础知识

    js执行时,在同一个作用域内是先解释再执行。解释的时候会编译function和var这两个关键词定义的变量,编译完成后从上往下执行并向变量赋值。  区分大小写  ECMASCript中的一切(包括变量,函数名和操作符)都...

    JavaScript常用基础知识强化学习

    首先,还是用比较官方的文字描述来解释下...JavaScript是一种解释型的脚本语言,C、C++等语言先编译后执行,而JavaScript是在程序的运行过程中逐行进行解释。 · 基于对象。JavaScript是一种基于对象的脚本语言,它不仅可

    毕业设计电商网站源码-fe_base_knowledge:我也来整理一份前端基础知识(面试题)

    前端基础知识,不断更新并补上对应的文章(答案) JavaScript let、const、var 的区别有哪些?- var可变量提升,可重复声明,无暂存死区,无块级作用域 自执行函数: var foo = 1 (function foo() { foo = 10 console....

    Knowledge-Map:知识图

    前端知识地图原生JS名词与基础概念基础概念javascript是单线程语言在浏览器中,一个页面只有一个线程执行JS代码。 javascript是异步执行的,通过事件循环(Event Loop)的方式实现代码解析十分Swift,不会发生解析...

    leetcode分类-blog::cookie:我的博客

    JavaScript基础知识 声明 内置类型 typeof 的使用 数据类型转换 转义字符 运算符 调用堆栈 全局执行上下文 函数执行上下文 eval执行上下文 执行上下文栈和变量对象 变量提升 函数提升 分配内存 使用内存(读写) 释放...

    Grails权威指南

     3.6.2 日志记录(logging)和环境  3.7 grails命令行工具  3.7.1 在不同的端口上运行grails应用程序  3.7.2 打包war存档文件(warcarchive)  3.8 使用grails控制台(console)及命令解释程序...

    php网络开发完全手册

    2.2.3 变量的作用域 27 2.2.4 动态变量 29 2.3 运算符和关键字 29 2.4 流程控制语法 30 2.4.1 程序控制语句的简介 30 2.4.2 条件控制语句 30 2.4.3 循环控制语句 33 2.4.4 转移控制语句 35 2.5 表达式 36 2.5.1 简单...

    JSP动态网站开发基础教程与实验指导(从基础到应用)光盘

    7.2.3 JavaBean作用域范围 158 7.3 设置或获取JavaBean属性 162 7.3.1 设置JavaBean属性 162 7.3.2 获取JavaBean属性 165 7.4 扩展练习 168 第8章 Servlet技术 171 8.1 Servlet简介 171 8.1.1 Servlet概述 171 ...

    精通AngularJS part1

    学习$q服务的基础知识85 promise是第一类JavaScript对象87 聚合回调88 注册回调和承诺的生命周期88 异步动作的链式调用89 关于$q的其他91 AngularJS中的$q集成93 33promiseAPI与$http94 34与RESTful端点通信...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    JavaScript作用域 JavaScript面向对象及原型 Dom选择器以及内容文本操作 Dom样式操作 Dom属性及创建标签 Dom提交表单及其他 Dom事件操作 Dom事件操作补充 Dom绑定时间的另外一种方式 JavaScript 词法分析解析 前端...

    JavaScript高级教程

    3.4.1 公用、受保护和私有作用域..............................................75 3.4.2 静态作用域并非静态的..............................................76 3.4.3 关键字 this. 76 3.5 定义类或对象...........

    Flex企业应用开发实战源代码

    首先介绍了Flex/Flash的工作机理和利用Flex开发企业级应用必须掌握的基础知识和核心元素;接着剖析了Flex与Java的通信机制,以及Flex企业应用的客户端架构和服务器端架构;再接着详细讲解了BlazeDS框架的使用方法和...

    asp.net知识库

    事务隔离性的一些基础知识 在组件之间实现事务和异步提交事务(NET2.0) 其它 在.NET访问MySql数据库时的几点经验! 自动代码生成器 关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 发布Oracle...

    PHP和MySQL Web开发第4版pdf以及源码

    4.6.1 基础知识 4.6.2 字符集和类 4.6.3 重复 4.6.4 子表达式 4.6.5 子表达式计数 4.6.6 定位到字符串的开始或末尾 4.6.7 分支 4.6.8 匹配特殊字符 4.6.9 特殊字符一览 4.6.10 在智能表单中应用 4.7 用...

    Tcl_TK编程权威指南pdf

    place的基础知识 面板管理器 place命令 第26章 将命令与事件编联 bind命令 bindtags命令 事件的语法 修饰符 事件序列 虚拟事件 事件关键词 第4部分 tk组件 第27章 按钮与菜单 按钮命令与作用域问题 ...

    PHP和MySQL WEB开发(第4版)

    4.6.1 基础知识 4.6.2 字符集和类 4.6.3 重复 4.6.4 子表达式 4.6.5 子表达式计数 4.6.6 定位到字符串的开始或末尾 4.6.7 分支 4.6.8 匹配特殊字符 4.6.9 特殊字符一览 4.6.10 在智能表单中应用 4.7 用正则表达式...

    精通JS脚本之ExtJS框架.part2.rar

    4.4.2 函数的作用域 4.4.3 Ext.lib.Event事件 4.4.4 Ext.util.Observable事件 4.4.5 Ext.EventManager事件 4.4.6 Ext.EventObject事件 4.5 各种事件登记方式 4.5.1 传统式登记 4.5.2 内联式登记 4.5.3 Dom ...

    精通JS脚本之ExtJS框架.part1.rar

    4.4.2 函数的作用域 4.4.3 Ext.lib.Event事件 4.4.4 Ext.util.Observable事件 4.4.5 Ext.EventManager事件 4.4.6 Ext.EventObject事件 4.5 各种事件登记方式 4.5.1 传统式登记 4.5.2 内联式登记 4.5.3 Dom ...

    webBlog:记录前段知识点

    NodeCSSJavaScriptJS 基础复杂数据类型JS运算符数据类型检测数据类型转换JS预编译JS原型-原型链JS执行上下文thisJS闭包箭头函数变量、作用域、内存问题高阶迭代器和生成器事件循环机制EventLoop总结JS元编程...

Global site tag (gtag.js) - Google Analytics