函数的作用域链的理解

1.作用域(scope):在javascript没有块级作用域,是由函数来划分的。变量和函数的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域(with和eval除外)。当定义了一个函数,当前的作用域链就保存起来,并且成为函数的内部状态的一部份。在最顶级作用域链仅由全局对象组成,而不和词法作用域相关,然而,当定义一个嵌套的函数时,作用域链就包括外面的包含函数。这意味着嵌套函数可以访问包含函数的所有参数和局部变量。尽管当一个函数定义时作用域链就固定了,但作用域链中定义的属性还没有固定。作用域链是活的,并且函数被调用时,可以访问任何当前的绑定。
2.作用域链(scope chain):存储变量对象的集合(环境栈?),保证对执行环境有权访问的所有变量和函数的有序访问,也就是用于标识符解析(变量访问)。
3.执行环境(execution context):定义了变量和函数有权访问的其他数据,决定了它们的各自行为。每个执行环境都有一个与之关联的变量对象。
在web浏览器中,window对象就是全局执行环境。每个函数都有自己的执行环境,当函数执行完毕,该环境被销毁,保存在其中的变量和函数也随之销毁。
4.变量对象(variable object):保存了环境中定义的所有变量和函数。该对象无法访问,仅供解析器在后台使用。
5.活动对象(activation object):如果执行环境是函数,则将其活动对象作为变量对象(调用对象?)。活动对象最开始的两个属性是arguments和this

一、作用域链

a) 一个函数创建时,javascript后台(引擎)会默认创建一个仅供后台使用的内部属性[[Scope]],此属性存储函数的作用域链,如果是全局函数,此时则包含一个变量对象(全局变量),如果是嵌套函数(闭包),作用域链还加上了父函数的变量对象。例如下面的这个全局函数:

function add(num1,num2){
   var sum = num1 + num2;
   return sum;
}

(此图是函数定义时的作用域链)

b) 函数被调用时--add(5,10),javascript后台会创建一个内部对象(execution context)--“执行环境”或“运行期上下文”,执行环境有它自己的作用域链,执行环境创建时就以定义函数时的作用域链初始化它自己的作用域链,并且随后创建了一个活动对象,活动对象作为函数执行期的一个变量对象,包含所有局部变量(在函数内定义的)、命名参数、arguments、this,它会被推入到执行环境作用域链的前端(如下图)。每执行一次函数都会创建一个新的执行环境,当函数执行完毕执行环境就会被销毁。

(此图是函数运行时的作用域链)

另外关于延长作用域链问题:以下的两种情况会使作用域链延长

1) try-catch语句的catch块;

2) with语句;

这个两个语句都会再原本的作用域链的前端添加一个变量对象。对于with语句来说,新添加的变量对象包含着with括号中指定对象的所有属性和方法所作的变量声明。对于catch来说,当try块发生错误时,代码执行流程自动转入到catch块,并将异常对象推入到作用域链的前端。catch块执行完毕后,作用域链就会返回原来的状态

请看下面的例子:

function initUI(){
   with(document){
        var bd = body,
        links =  getElementsByTagName("a"),
        i = 0,
        len = links.length;
        while(i<len){
              update(links[i++]);
        }
        getElementById("go-btn").onclick = function(){
              start();
        };
        bd.className = "active"
   }
}

当代码流执行到一个with表达式时,执行环境的作用域链会被临时改变,此时with的变量对象会被创建添加到作用域链的前端,这就意味着此时函数的所有局部变量都被推入到第二个作用域链中的变量对象,如下图:

由上图可清晰的看到,在执行with语句时,访问局部变量的代价更高了。所以尽可能避免使用with语句,可以使用局部变量代替

var doc = document; // 代替with(document){...}
时间: 2024-12-16 16:47:40

函数的作用域链的理解的相关文章

函数的作用域链是由函数定义时所决定的而非调用

废话不多说,上代码: 案例1 <!doctype html> <html> <head> <meta charset="utf-8"> <title>Test</title> <script> function a() { var flag = true; b(); } function b() { console.log( flag ); } a(); </script> </hea

JavaScript基础--函数声明,函数的作用域链

函数声明和函数表达式区别 函数声明是通过 function 函数名(){}来声明一个函数 函数表达式是通过声明一个变量,然后赋值函数. 两者区别是,在程序执行前,会先获取函数声明声明的函数,获取变量的声明,这里变量的声明只是先开辟一个空间,然后给了个名字,之后到该变量名赋值的时候,才有值,也就是说,在未得到该变量的赋值前,使用该变量会得到undefined. 而无论你把函数放在放在程序中的开头或者结尾,函数的执行语句都能正常执行. fn();//输出   fnconsole.log(fn2);/

一、关于作用域 作用域链的理解

作用域:每个函数有自己执行环境(个人理解即作用域),而其执行环境决定了那个环境中的变量和函数可以访问的数据的权限. 作用域链:从当前执行环境往外部检索(当前环境为此作用域链的最前端,全局环境为作用域链尾部),第一种情况检索成功,直到检索到对应变量为止:第二种情况检索失败,即找到全局环境还未找到相对应的变量,返回not defined的错误. 例:function scopetest1() { var test1 = 1;            //可访问test1 function scopet

js的作用域与作用域链的理解(转)

一直对Js的作用域有点迷糊,今天偶然读到Javascript权威指南,立马被吸引住了,写的真不错.我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫. 一:函数作用域 先看一小段代码: 第一句输出的是: "undefined",而不是 "global" 第二讲输出的是:"local" 你可能会认为第一句会输出:"global",因为代码还没执行var scope="local&qu

对作用域和作用域链的理解

理解好javascript的变量作用域和链式调用机制对用好变量起着关键的作用,下面我来谈谈这两个概念的理解. (1)链式调用机制 作用域链的定义:函数在调用参数时会从函数内部到函数外部逐个"搜索"参数,一直找到参数为止,如果没有声明就返回null,声明了没有赋值就返回undefined,就像沿着一条链子一样去搜索,这就是作用域的链式调用. javascrip的变量作用域跟python或者其他后端语言不同,变量一经声明,它的作用域就是全局的.在函数内部如果调用一个变量,就会发生上述的作用

函数的作用域链在定义时已经确定!!

最近看到一个面试题如下: var x=10; function fn() { console.log(x); } function show(f) { var x=20; (function() { f(); })(); } show(fn); //10 最后的输出结果是10而不是20,是不是很差异,不是有作用域链吗,不是内部函数有权访问外部函数的变量吗,世界怎么了,之前的理论都崩塌了吗??囧... 其实不是的,之前的理论没错,只是自己的理解有问题.函数执行时确实是沿着作用域链查找变量的,问题是

爱创课堂每日一题第八天说说你对作用域链的理解?

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的.

深入理解javascript中执行环境(作用域)与作用域链

相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行环境分为全局执行环境和局部执行环境,其中局部执行环境我们又可以称之为函数执行环境.那么究竟什么使执行环境呢?通俗的说,执行环境即为代码执行时所处的环境.我们下来看一看如下代码,再进一步分析之. 1 2 3 4 5 6 7 8 9 10 11 <script><br>var name="zhuzhenwei"; functio

深入理解作用域链

作用域链是JavaScript中的一个非常重要的概念,想要理解什么是作用域链,就必须知道什么是作用域. 作用域: 1.全局作用域: (1)最外层函数和在最外层函数定义的变量,拥有全局的作用域.js中一切皆对象,函数也是对象,js最外层的对象是window.所以在window下定义的函数和未被这些函数包裹的变量,就拥有全局作用域,这些变量能够在其他任何作用域下使用. (2)所有window对象下的内置属性属于全局变量:如window.document,window.navigator等. (3)没