最近想整理一下js执行代码的一些知识,如果有出错的地方还请指正。

  执行环境(Execution Context)

  所有的javascript代码都是在一个执行环境中被执行的。它只是一种机制,用来完成运行时作用域、生存期等方面的处理。

  代码分为三种类型:

  1.   Global Code
  2.   Eval Code
  3.   Function Code

  这是一个EC结构

可以理解如下:

activeExecutionContext = {
VO: {...}, // or AO
this: thisValue,
Scope: [ // Scope chain
// 所有变量对象的列表
// for identifiers lookup
]
};

  当一段程序开始时,会先进入到全局执行上下文环境。此时如果调用了某些函数,就会进入他们的上下文环境,执行完之后再退出该上下文环境。

假设激活了一个EC1的上下文,图解如下

  变量对象(VO)和活动对象(AO)

  变量对象是一个与上下文相关的数据作用域,用于存储被定义在上下文中的变量和函数声明(不包括函数表达式)。在global全局上下文中,变量对象即使全局对象自身。

copy一个例子

var foo = ;

function bar() {} // // 函数声明
(function baz() {}); // 函数表达式 console.log(
this.foo == foo, // true
window.bar == bar // true
); console.log(baz); // 引用错误,baz没有被定义

全局上下文中的变量对象(VO)会有如下属性:

在一个函数的上下文中,变量对象被表示为活动对象

活动对象在进入上下文中初始化成了

AO = {
arguments: <ArgO>
};

arguments属性值就是Arguments对象

之后就是存储当前上下文的变量与函数声明

  作用域链

  作用域链是一个 对象列表,用于检索上下文中出现的 标识符(变量名称、函数声明,普通参数)。

  在函数创建的时候,当前的作用域链被存储到了函数的[[scope]]属性中。当进入上下文创建AO/VO之后,上下文(EC)的Scope属性作了如下处理:

Scope = AO|VO + [[Scope]]

  知识点就是这些,现在我们来一段代码,把过程给串联起来。在这之前,我们要知道另一个知识,就是执行上下文的代码被分成两个基本的阶段来处理

  1. 进入执行上下文
  2. 执行代码
var x = ;

function foo(m) {
var y = ; function bar() {
var z = ;
alert(x + y + z + m);
} bar();
} foo(10); //

首先先进入全局上下文环境

  全局上下文的变量对象(代码执行时,x才被赋值)是:

globalContext.VO === Global = {
x:
foo: <reference to function>
};

globalContext.Scope = globalContext.VO;

当"foo"创建时,

foo.[[Scope]] = [
globalContext.Scope
];
//也就是
foo.[[Scope]] = [
  globalContext.VO
];

在"foo"激活时,进入了foo的上下文,foo上下文中的活动对象(代码执行时,y才被赋值)是:

fooContext.AO = {
 arguments:<Arg>,
 m: 10,
 y: ,
bar: <reference to function>
};

此时foo上下文中的作用域链为:

fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.:

fooContext.Scope = [
fooContext.AO,
globalContext.VO
];

函数"bar"创建时,其[[scope]]为:

bar.[[Scope]] = fooContext.Scope;
//也就是
bar.[[Scope]] = [
fooContext.AO,
globalContext.VO
];

同理,bar就不写了。最后bar上下文的作用域链为:

barContext.Scope = barContext.AO + bar.[[Scope]] 

barContext.Scope = [
barContext.AO,
fooContext.AO,
globalContext.VO
];

在alert执行时,作用域链中查找标示符如下

查找 x,  barContext.AO 无 ----> fooContext.AO 无 ---->globalContext.VO 有

查找 Z,  barContext.AO 有

其他的就自己看了。

  局部变量、全局变量

  在作用域链中查找标识符是需要花时间的,所以就明白为什么需要尽量使用局部变量(将频繁使用的全局变量缓存下来),全局变量尽量少用了。并且with会破坏作用域链,它会将指定的VO/AO加入到作用域链的顶端,这样在标识符查找时,需要查找更长的作用域链。

  闭包

  理解了上面的概念,闭包就很容易理解了。闭包是代码块和创建该代码块的上下文中数据的结合。

  

javascript 作用域链的更多相关文章

  1. JavaScript作用域链的理解

    前言 作用域是JavaScript一个很重要的概念,想要学好JavaScript就需要理解javascript作用域和作用域链的工作原理.这篇文章对JavaScript作用域链和作用域链做一个简单的介 ...

  2. JavaScript 作用域链图具体解释

    <script type="text/javascript"> /** * 作用域链: */ var a = "a"; function hao94 ...

  3. JavaScript作用域链

    之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...

  4. 个人理解的javascript作用域链与闭包

    闭包引入的前提个人理解是为从外部读取局部变量,正常情况下,这是办不到的.简单的闭包举例如下: function f1(){ n=100; function f2(){ alert(n); } retu ...

  5. javascript作用域链学习笔记

    作用域链 "JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里." --权威指南 在JavaScript中,一切皆对象,包括函数.函数对象和其它对象 ...

  6. (好文推荐)一篇文章看懂JavaScript作用域链

    闭包和作用域链是JavaScript中比较重要的概念,首先,看看几段简单的代码. 代码1: var name = "stephenchan"; var age = 23; func ...

  7. 深入javascript作用域链到闭包

    我之前用过闭包,用过this,虽然很多时候知道是这么一回事,但是确实理解上还不够深入.再一次看javascript高级程序设计这本书时,发现一起很多疑难问题竟然都懂了,所以总结一下一些理解,难免有错, ...

  8. 图解 javascript 作用域链

    还是之前那一段简单的javascript代码: window.onload=function(){ function sub(a,b){ return a-b; } var result=sub(10 ...

  9. JavaScript作用域(链)学习笔记

    作用域是javascript老生常谈的问题,在面试题中也经常出现.此文记录本人对js作用域的理解.从以下三个方面深入探讨js作用域和js作用域链. 1.什么是作用域? 2.什么是作用域链? 3.常见面 ...

  10. JavaScript作用域链详解

    JavaScript的作用域链还是很有味道的,搞懂了这个知识点,闭包的问题也就迎刃而解咯 1.JavaScript的全局变量和局部变量 首先,先来看看js的全局变量和局部变量,js不是块级作用域,所以 ...

随机推荐

  1. C语言 大小端 字节对齐

    参考:http://www.cnblogs.com/graphics/archive/2011/04/22/2010662.html 1. 大端序:数据的高位字节存放在地址的低端,低位字节存放在地址的 ...

  2. at org.apache.jsp.index_jsp._jspInit(index_jsp.java:23)异常解决

    部署项目,启动tomcat一切正常.输入项目地址后 tomcat报例如以下错误: java.lang.NullPointerException at org.apache.jsp.index_jsp. ...

  3. C#后台创建控件并获取值

    前台代码 <form id="form1" runat="server"> <div> <div class="item ...

  4. 错误提示:在此上下文中不允许使用名称 "***"。有效表达式包括常量、 常量表达式和变量(在某些上下文中),不允许使用列名。

    出现这种情况的原因,是因为在SQL语句的编写格式不正确. 事例展示: 错误: string sql = "insert into person ([name], sex, salary) v ...

  5. Java socket字节流传输的示例

    服务端server端: package com.yuan.socket; import java.io.*; import java.net.ServerSocket; import java.net ...

  6. JAVA 语 言 如 何 进 行 异 常 处 理 , 关 键 字 : throws,throw,try,catch,final

    throws是获取异常throw是抛出异常try是将会发生异常的语句括起来,从而进行异常的处理,catch是如果有异常就会执行他里面的语句,而finally不论是否有异常都会进行执行的语句.

  7. vi、vim 配置上下左右方向键和删除键

    vi.vim 配置上下左右方向键和删除键 " An example for a vimrc file. " " Maintainer: Bram Moolenaar &l ...

  8. 常用Android快速开发框架

    在做项目的过程中遇到了很多困难,于是收集了一些快速开发的框架,使用后大大提高了项目开发速度,无论什么项目都可以使用的到,在此分享给大家,希望能对大家有帮助!(个人建议:有时间的同学可以看一下这些优秀框 ...

  9. bzoj 2542: [Ctsc2001]终极情报网 费用流

    题目链接 2542: [Ctsc2001]终极情报网 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 321  Solved: 125[Submit][S ...

  10. python初探-数据类型

    数据类型 可以使用BIF type()来查看对象的类型 数字 int float long 布尔(bool) True 机内表示1,机器识别非0 False 机内表示0,机器识别0 空值 None 字 ...