本章,我们讨论一下ECMAScript中的作用域链 , 开门见山。

什么是作用域链

i.ECMAScript是允许创建内部函数的,甚至能从父函数中返回这些函数。作用域链正是内部上下文中所有变量对象(及自由对象)的列表。此链用来变量解析查询。

作用域链的特性

i.是执行上下文的一个属性

activeExecutionContext = {
vo : {},
this : thisValue,
scope : []
}

ii.逻辑上是一个数组,每一个元素是一个变量对象

iii.定义为:Scope = ActiveContext.VO + Function.[[Scope]]  ([[Scope]] 是函数的属性)

理解作用域链

i.[[Scope]] 是函数的私有属性,在函数被解析时创建,不会改变。

  为了让大家更好的理解,先让大家看一段代码:

var x = 'test';

function foo() {
console.log(x);
} (function() {
var x = 'what'; foo();
})();

上面的代码输出会是什么呢?为什么?

控制台将会输出 'test',而非 'what' 。这个例子也说明,一个函数的[[Scope]] 持续存在,即使是在函数创建的作用域已经完成之后。

ii.[[Scope]] “通常”(存在意外) 包含了父级函数的[[Scope]]属性,ECMAScript依靠这个特性来实现闭包。

iii.[[Scope]]是函数的属性,这也意味着ECMAScript中没有Java那样的块级作用域。(ES6中对这一块得到了加强)只有函数级作用域。

观察以下3种函数构造方式的差异:

var x = 10;

function foo() {
var y = 20; // 函数声明方式创建
function innerFoo() {
console.log(x ,y);
} //函数表达式方式创建
var innerFoo2 = function() {
console.log(x ,y);
} //构造函数方式创建
var innerFoo3 = Function('console.log(x);console.log(y);'); innerFoo(); //10 20
innerFoo2(); //10 20
innerFoo3(); //10 ,y not defined
}

通过以上代码,我们可以看出,通过Function构造函数创建的方法只拥有全局作用域

iiii.变量的二维链式查找

   变量的解析是通过作用域链来实现的。

变量本质是上以变量对象的属性方式存在,当变量对象与JavaScript中对象重叠时,它就会天然的受到原型链的影响。

一段有趣的代码:

function foo() {
console.log(x);
} Object.prototype.x = 10; foo(); //

原因: 此时,全局对象为 window(假设在浏览器中运行该段代码),而window对象是Object所派生的。根据原型链查找规则,实例中访问不到的属性和方法,将会在原型中查找。

以下面的代码为例,其查找顺序是这样的:

iiiii.全局代码和 eval 的作用域链

全局代码中的作用域链仅包含全局对象

eval的上下文与当前 calling context(调用上下文) 拥有相同的作用域链

ES5中规定,如果对eval建立别名(非直接调用),这时作用域链仅包含全局对象

iiiiii.作用域链是可以在运行时动态改变的

在with 和 catch 语句中:Scope = withObject || catchObject + VO + [[Scope]]

大多数情况下是不变的,但在with语句和catch语句块中,可以改变作用域链。这种技巧在有些时候非常有用,但大多数情况下,我们要尽可能避免

ES5中,通过词法环境、词法环境记录的方式来扫描这种变化

根据我们上面讲到的,大家看看如下代码:

var x = 10,
y = 10; with({x: 20}) {
var x = 30 ,
y = 30;
console.log(x ,y); // 30 30
} console.log(x ,y); // 10 30

输出的结果是: 30 30   10 30 ,为什么呢?实际上上面讲到的作用域链的动态改变时,已经对该问题做出了解答, 下面我们分析一下:

在with和catch语块中的作用域链:

1.x = 10 ,y = 10;

2.对象{x:20}被添加到了作用域的前端

3.在with内部,遇到了var声明。但是什么也没创建,因为在进入上下文时,所有变量已被解析添加

4.在步骤2中,仅修改变量'x' ,实际上对象中的'x'现在被解析,并添加到作用域链的前端,'x'由 20 变为 30

5.同样也有变量对象的属性'y'的修改,被解析后其值也由10变为30

6.此外,在with声明完后,它的特定对象从作用域链中移除,(已改变的变量“x”--30也从那个对象中移除),即作用域链的结构恢复到with得到加强以前的状态。

7.最后console中,当前变量对象 'x'保持相同,'y'的值 = 30(在with声明运行中已发生改变)

iiiiiii.结合this一起

直接调用函数,作用域为 withObject

var x = 10; 

with({
foo : function() {
console.log(this.x);
} ,
x : 20
}) {
foo(); //
}

总结

理解执行上下文、VO(变量对象)、this、作用域链是理解JavaScript执行的基础,尤其是this和作用域链

Scope Chain(作用域链)的更多相关文章

  1. JS -- The Scope Chain 作用域链

    The Scope Chain JavaScript is a lexically scoped language: the scope of a variable can be thought of ...

  2. JavaScript的语法要点 2 - Scope Chain

    前文所述,JavaScript是基于词法作用域(lexically scoped)的,所以标识符被固定在它们被定义的作用域而不是语法上或是其被调用时的作用域.即全局变量的作用域是整个程序,局部变量的作 ...

  3. javascript 执行环境,变量对象,作用域链

    前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体. 通过上网查资料,特来总结,以备回顾和修正. 要讲的依次为: EC( ...

  4. javascript 之作用域链-10

    前言 在<执行环境>文中说到,当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文(execution context). 变量对象(Variable object,VO ...

  5. VO、AO、执行环境和作用域链

    1.变量对象(variable object) 原文:Every execution context has associated with it a variable object. Variabl ...

  6. JavaScript——执行环境、变量对象、作用域链

    前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体.通过上网查资料,特来总结,以备回顾和修正. 目录: EC(执行环境或 ...

  7. JavaScript 作用域链解析

    JavaScript 中有 Scope( 作用域 ) , Scope chain( 作用域链 ) , Execute context( 执行上下文 ) , Active Object ( 活动对象 ) ...

  8. 【转】javascript 执行环境,变量对象,作用域链

    这篇文章比较清晰的解释了一些作用域链相关的概念,忍不住收藏了 原文地址:http://segmentfault.com/a/1190000000533094 前言 这几天在看<javascrip ...

  9. (翻译) How variables are allocated memory in Javascript? | scope chain | lexicial scope

    总结: 阅读下面文章需要15分钟 提问者的问题是JavaScript中内存是怎么分配的,在介绍的过程作者涉及计到了JS中 Scope Chain和调用函数call生成lexicial environm ...

随机推荐

  1. 学习Swift -- 继承

    继承 一个类可以继承另一个类的方法(methods),属性(properties)和其它特性.当一个类继承其它类时,继承类叫子类,被继承类叫超类(父类). 在 Swift 中,子类可以调用和访问父类的 ...

  2. codevs 1066 引水入城

    传送门 题目描述 Description 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政 区划十分特殊,刚好构成一个N行M列的矩形,如上图所示,其中每个格子都代表一座城 ...

  3. 对rsync进行封装的shell脚本

    抓取 #!/bin/bash . push.sh # 错误处理:尝试查找备份文件 function onError() { local errFile="err" local se ...

  4. Contest 20140914 Mushroom写情书 字符串雙hash 後綴數組

    0111:Mushroom写情书 查看 提交 统计 提问 总时间限制:  10000ms 内存限制:  256000kB 描述 有一天,Mushroom准备向他的GF表白,为了增加表白成功率,Mush ...

  5. 实现pushViewController:animated:的不同页面转换特效

    1. 首先要明确的是,不使用pushViewController的默认动画,所以在调用这个函数时,要将animated设置为NO.2. 使用普通的来CATransition实现转换效果,代码如下:CA ...

  6. ibatis把表名作为一个参数报错问题的解决方案

    用ibatis的时候,想把表名也作为一个参数传进去,可是报错了,在ibatis配置文件里面是#resource#的方式,报错信息如下: org.apache.cxf.interceptor.Fault ...

  7. Weblogic8.1 的性能优化

    注:在下面做的介绍都是以Weblogic8.1为例的,其它版本的Weblogic可能会有些许不同. 1) 设置JAVA参数: a) 编辑Weblogic Server启动脚本文件: BEA_HOMEu ...

  8. 【CF】556D A Lot of Games

    构建trie树,可以得到4类结点:必胜点,必负点,完全主宰点(可胜可负),完全无法主宰点(无法控制最终胜负).递归到叶子结点,即为必胜点,回溯分情况讨论.注意叶子结点使用属性n来控制,n表示当前结点的 ...

  9. mongodb exception in initAndListen: 12596 old lock file, terminating 解决方法

    错误信息如下: exception in initAndListen: 12596 old lock file, terminating 基本上都是由于服务器断电等异常中断重启引起 解决方法 1.删除 ...

  10. 【转】MFC窗口句柄各类指针获取函数

    原文网址:http://www.pythonschool.com/CPP_JHK/5003.html 获取所在类窗口的句柄 this->m_hwnd; // this是一个指针,指向当前类的实例 ...