在学习JavaScript作用域概念之前,首先要明白几个概念:执行环境、变量对象、作用域链。

一、JavaScript执行环境(execution context):

在《Professional JavaScript for Web Developers》一书中写到:

The concept of execution context, referred to as contextfor simplicity, is of the utmost importance in JavaScript. The execution context of a variable or

function defines what other data it has access to, as well as how it should behave. Each execution context has an associated variable objectupon which all > of its defined variables and functions exist. This object is not accessible by code but is used behind the scenes to handle data.

在对应的《JavaScript高级程序设计》一书翻译是这样的:

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

全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完后,该环境被销毁,保存在其中的 > 所有变量和函数定义也随之销毁。(全局执行环境直到应用程序退出-例如关闭网页或者浏览器时才会被销毁。

二、全局作用域和局部作用域

1.全局作用域(Global Scope):在代码中任何地方都能访问到的对象拥有全局作用域

(1)最外层函数和在最外层函数外面定义的变量拥有全局作用域

var authorName="山边小溪";
function doSomething(){
var blogName="梦想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName); //山边小溪
alert(blogName); //脚本错误
doSomething(); //梦想天空
innerSay() //脚本错误

(2)所有末定义直接赋值的变量自动声明为拥有全局作用域

function doSomething(){
var authorName="山边小溪";
blogName="梦想天空";
alert(authorName);
}
doSomething(); //山边小溪
alert(blogName); //梦想天空
alert(authorName); //脚本错误

变量blogName拥有全局作用域,而authorName在函数外部无法访问到。

(3)所有window对象的属性拥有全局作用域

一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等

2.局部作用域:和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域,例如下列代码中的blogName和函数innerSay都只拥有局部作用域。

function doSomething(){
var blogName="梦想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误

我们再来看一个具体的实例:

var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但不能访问 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();

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

环境。全局环境中有一个变量 color 和一个函数 changeColor() 。 changeColor() 的局部环境中有一个名为 anotherColor 的变量和一个名为 swapColors() 的函数,但它也可以访问全局环境中的变量 color 。 swapColors() 的局部环境中有一个变量 tempColor ,该变量只能在这个环境中访问到。无论全局环境还是 changeColor() 的局部环境都无权访问 tempColor 。然而,在 swapColors() 内部则可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境。图 4-3 形象地展示了前面这个例子的作用域链。

图中的矩形表示特定的执行环境。其中,内部环境可以通过作用域链访问所有的外部环境,但

外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都

可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个

执行环境。对于这个例子中的 swapColors() 而言,其作用域链中包含 3 个对象: swapColors() 的变量对象、 changeColor() 的变量对象和全局变量对象。 swapColors() 的局部环境开始时会先在自己的变量对象中搜索变量和函数名,如果搜索不到则再搜索上一级作用域链。 changeColor() 的作用域链中只包含两个对象:它自己的变量对象和全局变量对象。这也就是说,它不能访问swapColors() 的环境。

三、JavaScript作用域链(scope chain)

作用域链创建:

当代码在一个环境中执行时,会创建变量对象的一个作用域。

作用域链功能:

作用域链:保证对执行环境有权访问的所有变量和函数的有序访问。

作用域链顺序:

1. 作用域的前端,始终是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象:在最开始时只包含一个变量,即arguments对象(这个对象在全局环境中不存在)

2. 作用域链中的下一个变量对象来自包含(外部)环境
3. 再下一个变量对象则来自下一个包含环境。
4. 这样,一直延续到全局执行环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象。

解析

标识符解析是沿着作用域链一级一级地搜索标识符的过程。

搜索

搜索过程始终是从作用域的前端开始,逐级向后回溯,直至找到标识符为止(找不到,通常会报错)。

举例

任何执行上下文时刻的作用域, 都是由作用域链(scope chain)来实现.

在一个函数被定义的时候, 会将它定义时刻的scope chain链接到这个函数对象的[[scope]]属性.

在一个函数对象被调用的时候,会创建一个活动对象(也就是一个对象), 然后对于每一个函数的形参,都命名为该活动对象的命名属性, 然后将这个活动对象做为此时的作用域链(scope chain)最前端, 并将这个函数对象的[[scope]]加入到scope chain中.

 var func = function(lps, rps){
var name = 'laruence';
........
}
func();

解析

在执行func的定义语句的时候, 会创建一个这个函数对象的[[scope]]属性, 并将这个[[scope]]属性, 链接到定义它的作用域链上, 此时因为func定义在全局环境, 所以此时的[[scope]]只是指向全局活动对象window active object.

在调用func的时候, 会创建一个活动对象(假设为aObj, 由JS引擎预编译时刻创建),并创建arguments属性, 然后会给这个对象添加俩个命名属性aObj.lps, aObj.rps; 对于每一个在这个函数中申明的局部变量和函数定义, 都作为该活动对象的同名命名属性.

然后将调用参数赋值给形参数,对于缺少的调用参数,赋值为undefined。

然后将这个活动对象做为scope chain的最前端, 并将func的[[scope]]属性所指向的,定义func时候的顶级活动对象, 加入到scope chain.

有了上面的作用域链, 在发生标识符解析的时候, 就会逆向查询当前scope chain列表的每一个活动对象的属性,如果找到同名的就返回。找不到,那就是这个标识符没有被定义

作用域其实是Function对象实例的一个内部属性【Scope】。函数被创建时候【Scope】这个内部属性包含了这个函数的作用域内所有对象的集合,这个集合叫做作用域链,作用域链决定了函数能访问到那些数据。

<script type="text/javascript">
function add(a,b)
{
var sum = a+b;
return sum;
}
</script>

 这是一个非常常见的函数,我们先定义好这个函数,记住先不执行它,当页面被加载,这个函数也会被初始化,记得前面我讲过,这样定义的函数是属于window的,加载页面时候会预编译的,这时候函数add的作用域链如下图:

四、执行上下文顺序

在进入执行上下文时候,会按照顺序执行下面的操作:

1.创建活动对象

活动对象是在进入执行上下文时候创建出来的,并且与新的执行上下文关联在一起。在初始化构造函数的时候,该对象包含一个arguments属性。激活对象在变量初始化也会用到。

2.创建作用域链

每一个函数都有一个内部属性[[scope]],它的值是一个包含多个对象的链。这个属性的具体指与函数的创建方式和代码中的位置有很大的关系。这一步的操作是把上一步创建的激活对象添加到函数的[[scope]]属性对应的链的前面。

3.变量初始化

对函数中需要用到的变量进行初始化。初始化时使用到的对象是前面创建的活动对象,不过这时还不能称作为变量对象。函数的实参、内部函数的局部变量是会被初始化

的。局部变量是在变量对象创建的过程中创建了同名的属性,这个属性值为undefined,在函数执行的过程中才会被真正的赋值。

ife task0003学习笔记(一):JavaScript作用域的更多相关文章

  1. ife task0003学习笔记(三):JavaScript闭包

    一.this易错分析 在学习闭包的时候,有一个概念this很重要,关于this的理解,下面3种情况:this指向谁? fn.call(obj1); obj2.fn() fn() 答案是obj1 obj ...

  2. ife task0003学习笔记(四):JavaScript构造函数

    JavaScript创建对象主要是3种方法:工厂模式.构造函数模式.原型模式.其实对于构造函数的概念,我们并不陌生.在之前学习c++语言的时候,也有提到过构造函数的概念.除了创建对象,构造函数(con ...

  3. ife task0003学习笔记(五):JavaScript面向对象

    JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.而在 JavaScript 中,this ...

  4. ife task0003学习笔记(二):JavaScript原型

    function aaa(){} aaa.prototype.bbb=function(){} var obj1=new aaa() var obj2=new aaa() obj1和obj2都有一个属 ...

  5. 微信小程序开发:学习笔记[5]——JavaScript脚本

    微信小程序开发:学习笔记[5]——JavaScript脚本 快速开始 介绍 小程序的主要开发语言是 JavaScript ,开发者使用 JavaScript 来开发业务逻辑以及调用小程序的 API 来 ...

  6. RX学习笔记:JavaScript数组操作

    RX学习笔记:JavaScript数组操作 2016-07-03 增删元素 unshift() 在数组开关添加元素 array.unshift("value"); array.un ...

  7. seaJs学习笔记之javascript的依赖问题

    之前分别为大家介绍了有关javascript中的冲突和性能问题,今天为大家介绍一下有关javascript中的依赖问题.我们将继续就之前javascript中性能问题继续介绍. 先来回顾一下性能问题的 ...

  8. 学习笔记:Javascript 变量 包装对象

    学习笔记:Javascript 变量 包装对象 如下代码,可以输出字符的长度. var str = "Tony"; str.length; 这时再试试以下代码,返回是 undefi ...

  9. 【学习笔记】JavaScript的基础学习

    [学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...

随机推荐

  1. SharePoint 2013备份方法整理

    关于SharePoint备份 SharePoint的备份是一个数据副本,主要用于在系统出现故障后还原和恢复该数据. 备份的工具主要有以下几种(写的不全,欢迎补充.) SharePoint管理中心的备份 ...

  2. ubuntu 下安装ffmpeg

    FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视 频的完整解决方案.它包含了非常先进的音频/视频编解码库 ...

  3. linux下利用httpd搭建tomcat集群,实现负载均衡

    公司使用运营管理平台是单点tomcat,使用量大,或者导出较大的运营数据时,会造成平台不可用,现在需要搭建tomcat集群,调研后,决定使用apache的httpd来搭建tomcat集群.以下是搭建步 ...

  4. 如果plsql连接没问题,但程序中报ORA-12504的错误

    说明程序中配置数据库连接的地方没有写tnsnames.ora中的SERVICE_NAME,或者SERVICE_NAME写的有错,检查一下,改正应该就好了

  5. 微服务架构下分布式事务解决方案——阿里云GTS

    https://blog.csdn.net/jiangyu_gts/article/details/79470240 1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这 ...

  6. XMLHttpRequest 与 Ajax 概要

    关于XMLHttpRequest 开发者使用XMLHttpRequest对象与服务端进行交互(发送http请求.接受返回数据等),可以在不打断用户下一步操作的情况下刷新局部页面.XMLHttpRequ ...

  7. [APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

    题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设 ...

  8. jenkins官方文档(中文版)

    https://www.w3cschool.cn/jenkins/

  9. Qt 学习之路 2(45):模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(45):模型 Qt 学习之路 2(45):模型  豆子  2013年2月26日  Qt 学习之路 2  23条评论 在前面两章的基础之上,我们 ...

  10. fiddler抓安卓

    1.tools connections  左 allow remote computersconnect  选中 2.配置模拟器 wifi 长按 修改网络 ip电脑ip 端口8888 ps:修改完不要 ...