执行环境和作用域

执行环境(execution context)是javascript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。

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

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

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

标示符解析是沿着作用域链一级一级地搜索标示符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直至找到标示符为止。

作用域链的本质是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

延长作用域链

虽然执行环境的类型总共只有两种—全局和局部,但还是有其他方法来延长作用域链。这么说是应为有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。在两种情况下。具体来说,就是当执行流进入下列任何一个语句时,作用域链就会得意加长:

Try-catch语句的catch块;

with语句

这两个语句都会在作用域链的前端添加一个变量对象。队with语句来说,会将制定的对象添加到作用域链中。队catch语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。

改变函数作用域

每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途就是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。

函数绑定:一个日益流行,在很多插件(jquery, backbone)中都能见到的一个技巧。函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。它常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同时保留代码执行环境。

ECMAScript 5为所有函数定义了一个原生的bind()方法,进一步简单了操作。

没有块级作用域

JavaScript没有块级作用域。在其他类C的语言中,由花括号封闭的代码块都有自己的作用域(如果用ECMAScriptd的话来讲,就是它们自己的执行环境),因而支持根据条件来定义变量。

if(true) {

var color = ‘blue’;

}

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

doSomething(i);

}

If for语句中的变量声明会将变量添加到当前的执行环境,for循环执行结束后,也依旧会存在于循环外部的执行环境中。

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

模仿块级作用域

通过匿名函数可以用来模仿块级作用域,语法如下:

(function() {

//这里是块级作用域

})()

以上代码定义并理解调用了一个匿名函数。将函数声明包含在一个圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一个圆括号会立即调用这个函数。

可以这样理解匿名函数:

var someFunction = function() {\

//这里是块级作用域

};

someFunction();

首先定义了一个函数,然后立即调用它。定义函数的方式是创建一个匿名函数,并把匿名函数复制给变量someFunction。而调用函数的方式是在函数名称后面添加一对圆括号,即someFunction()。那在这里是不是也可以用函数的值直接取代函数名呢?

function() {

//这里是块级作用域

}(); //报错!

这段代码会导致语法错误,是因为JavaScript将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号。然而,函数表达式的后面可以跟圆括号。要将函数声明转换为函数表达式只要给它家还是那个一对圆括号即可。

(function() {

//这里是块级作用域

})();

实际应用中,这样写法也可以

!function() {

}();

开头叹号“!“也可以换成”;” “+” “-”等。只不过阅读起来不如上面那种形式好理解。

PS:函数声明与函数表达式

函数声明与函数表达式区别在于:解析器子向执行环境中加载数据时对它们并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可以访问,这个重要特征就是函数声明提升(function declaration hoisting);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

转载于:https://www.cnblogs.com/purediy/archive/2012/09/12/2682455.html

[原]JavaScript必备知识系列-作用域相关推荐

  1. JavaScript基础知识系列:面向对象的编程

    JavaScript Basics is a series that explore some core concepts that every frontend software engineer ...

  2. javascript基础知识系列:DOM学习

    访问节点: 短距离的旅行: parentNode:获得父节点. firstChild:获得第一个子节点. lastChild:获得子节点的最后一个. 访问节点的文本: var  x=[a.paragr ...

  3. WCF分布式开发必备知识(4):Web Service(转)

    今天继续我们的WCF分布式开发必备知识系列文章的第4节:Web Service.前3节我们分别介绍了MSMQ消息队列/.Net Remoting/Enterprise Services三个相关的技术. ...

  4. 性能测试必备知识(7)- 深入理解“CPU 使用率”

    做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 回顾 CPU 使用率是单位时间内 CPU 使 ...

  5. 【JS】1037- 面试前必备的 JavaScript 基础知识梳理总结

    1. JavaScript简介 JavaScript 最开始是专门为浏览器设计的一门语言,但是现在也被用于很多其他的环境. 如今,JavaScript 已经成为了与 HTML/CSS 完全集成的,使用 ...

  6. 一些解密必备知识(2)- 基础篇03|解密系列

    一些解密必备知识(2)- 基础篇03 让编程改变世界 Change the world by program   软件安全是信息安全领域的重要内容,本系列视频教程将涉及到软件相关的加密.解密.逆向分析 ...

  7. 产品经理必备知识之网页设计系列(三)-移动端适配无障碍设计及测试

    前言 第一部分参见 产品经理必备知识之网页设计系列(一)-创建出色用户体验 https://blog.csdn.net/wenyusuran/article/details/108199875 第二部 ...

  8. 产品经理必备知识之网页设计系列(二)-如何设计出一个优秀的界面

    前言 第一部分参见 产品经理必备知识之网页设计系列(一)-创建出色用户体验 https://blog.csdn.net/wenyusuran/article/details/108199875 第三部 ...

  9. 产品经理必备知识之网页设计系列(一)-创建出色用户体验

    前言 设计师和开发人员在构建网站时,需要考虑很多事情,从视觉外观到功能设计. 本文将重点介绍创建出色用户体验的主要原则.方法和具有启发性的案例:从用户体验地图等整体结构开始,到单个页面的设计:还将介绍 ...

  10. JavaScript夯实基础系列(一):词法作用域

      作用域是一组规则,规定了引擎如何通过标识符名称来查询一个变量.作用域模型有两种:词法作用域和动态作用域.词法作用域是在编写时就已经确定的:通过阅读包含变量定义的数行源码就能知道变量的作用域.Jav ...

最新文章

  1. Python :给类或者类的对象添加打印内容 def __repr__(self)
  2. 启明云端分享|ESP32-C3阿里云连接测试
  3. 过拟合解决方法python_《python深度学习》笔记---4.4、过拟合与欠拟合(解决过拟合常见方法)...
  4. 【Tools】Visual Studio 2019搭建Qt开发环境
  5. log4j2自动删除_登录样式:log4j 2,上下文,自动清除…全部不附带任何字符串!...
  6. 对hash签名失败_vue项目中微信jssdk在ios签名失败
  7. webstorm 代码提示
  8. 现代程序设计 作业5
  9. Linux下使用fstatfs/statfs查询系统相关信息
  10. 传输层端口号的范围是多少?被分为哪两部分_根据资金习性可以把资金分为哪几类?_中级会计职称考试视频...
  11. java 鼠标动眼睛动_js动画_看着鼠标移动的眼球_眼睛_跟着随鼠标移动
  12. docker从C盘迁移到E盘
  13. C++的.cpp文件运行全过程
  14. 软件著作权源代码文档word操作技巧
  15. Spring - 事件监听机制 源码解析
  16. Ubuntu 18.04 安装Wine 微信
  17. IIB接收SAP请求配置
  18. 高等学校毕业生登记表计算机掌握程度,高等学校毕业生登记表自我鉴定三篇
  19. Armv8-R系列之ARM Cortex-R52 由来
  20. tomcat执行shutdown报错Could not contact [localhost:8005] (base port [8005] and offset [0]). Tomcat may n

热门文章

  1. 服务器定时备份数据库 执行文件
  2. Jhipster创建微服务【0】——踩坑
  3. 服务器双网卡导致的网络故障及解决方案
  4. Some Important Data Structures
  5. 文件系统03 - 零基础入门学习Delphi36
  6. 2步轻松搞定SpringBoot2.x分布式session共享,极少配置
  7. 运维半夜给我打电话,弹幕服务产生大量异常日志,没办法起床排bug...
  8. 不是我吹!超级全面的权限系统设计方案面世了
  9. 苹果爸爸发飙,封杀 React Native?
  10. Kotlin 1.0 正式版发布啦