`
lguoqing1001
  • 浏览: 47734 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

Javascript执行环境与作用域 转自博客园

阅读更多

定义

  执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中,

虽然我们编写的代码无法访问这个对象,但是解析器在处理数据的时候会在后台使用它

 

ü  全局执行环境

  全局执行环境是最外层的一个执行环境,根据实现所在的执行环境不同,表示执行环境的对象也不一样,在Web浏览器中,我们认为window对象就是全局执行环境,所有的变量及函数都是作为执行环境的属性或方法添加的

 

ü  

  每个函数在被调用的时候都会创建自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境

 

ü  作用域链

   当代码在一个环境中执行时,会创建由变量对象构成的一个作用域链,作用域链用是保证对执行环境的有权访问的所有变量和函数的有序访问。作用域链由当前执行的代码所在环境的变量对象,下一个变量对象同包含它的外部环境构成,再下一个变量对象则由包含下一个变量的外部环境构成。这样一直延续到全局执行环境

 

ü  标识符解析过程总是沿着作用域一级一级的向上搜索标识符

  示例:

        var outerVariable = "outer";

        function funcVariable() {
            var innerVariable = "inner";
        }

  对于funcVariable函数来讲,它的作用域链就包括两个对象,一个是自己的变量对象,另一个则是外部的全局变量对象,对于funcVariable函数来讲可以访问到变量outerVariable是因为可以在作用域链上找到该变量

我们可以从上得出结论,内部环境可以通过作用域链访问所有的外部环境,而外部环境是不能访问内部环境中的任何变量和函数的

  下面通过几个示例来分析一下javascript作用域相关内容

例1:

复制代码
     var name = "windowScope";
        var func = function () {
            var name = "function1";
            var func1Var = "function1_Variable";

            (function () {
                var name = "function2";
                var func2Var = "functioin2_Variable";

                alert("可以访问自身name、func1Var、func2Var、但是不能访问func3Var");

                (function () {
                    var name = "function3";
                    var func3Var = "functioin2_Variable";

                    alert(name); //不会得到"function2",因为在自身作用域中已存在
                       alert("可以访问自身name、func1Var、func2Var、func3Var");
                })();
})(); }; func();
复制代码

例2:

复制代码
     var func1 = function () {
            var func2Var = "function1";

            function function2() {
                var func2Var = "function2";

                inFunc2Var = " belong to function2 ?"; // 未用var声明,只要函数function2被调用,变量马上就变成全局变量
            }

            function2();
            alert(inFunc2Var);//no belong to function2
        }
        func1();
        alert(inFunc2Var);// 可以访问到变量inFunc2Var
复制代码

例3:

复制代码
     var variable = "outer";
        function funcVariable() {

            alert(variable);// undefined
            var variable = "inner";
            alert(variable)// inner
        }
        funcVariable();
复制代码

  上面也看了一些例子,下面来讲一讲作用域链是怎么样创建的 

ü  作用域链是如何创建的?

1.       当函数定义时,会将它定义时刻的作用域链(函数定义外部的作用域链)链接到函数对象的内部属性[[Scope]].

2.       当某一个函数被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性[[Scope]],然后使用this,arguments和其它命名参数的值来初始化函数的活动对象(activation object).

 

这样描述也不太直观,下面来参考一个例子讲解下作用域链是如何创建的

     var variable = "outer";
        function funcVariable() {
            var variable = "inner";
        }

 

  当如上函数被定义后,会创建一个预先包含全局变量对象的作用域链,并将这个作用域链保存在[[Scope]]

 

 

 

当调用函数funcVariable(),会为函数创建一个执行环境,此后会创建一个活动对象并被推入执行环境作用域链的前端如下图

 

 

 

 

  所以对于funcVariable来讲,其作用域链中包含了两个变量对象,一个是全局的一个是本地的.显然作用域链本质上是一个指向变量对象的指针列表,一般来讲当函数执行完毕后,局部活动对象就会被销毁,仅保存全局的作用域.另外当进行变量搜索的时候就会按照作用域链向上搜索,直到找到变量为止,没找到就会报错.

 

小结:

Javascript与其它语言差不多,在每次调用一个函数后,就进入函数的作用域,当离开函数的时候就返回调用前的作用域,

 

快结束了,再来看个问题,如上例3中代码,为什么第一次弹出为undefined,如下

 

复制代码
     var variable = "outer";
        function funcVariable() {

            alert(variable);// undefined
            var variable = "inner";
            alert(variable)// inner
        }
        funcVariable();
复制代码

 

 

Javascript特性var变量和function定义做预解析"

让我们来分析一下为什么第一个弹出来的是”undefined”,当运行以上代码时,javascript预解析功能便得知函数存在变量variable,而此时变量的值是undefined,以上代码相当于

 

复制代码
        var variable = "outer";
        function funcVariable() {
            var variable;
            alert(variable);// undefined
            variable = "inner";
            alert(variable)// inner
        }
        funcVariable();
复制代码

而在第二句调用alert函数时就发生了标识符搜索的过程,所以此时本地的活动对象中变量variable的值还是undefined,但是经过下一句赋值后,活动对象中的变量值就被修改为”inner”,再次访问就不会有问题.

分享到:
评论

相关推荐

    js-作用域-变量申明提升 - 甘劭 - 博客园1

    JavaScript中的作用域和变量声明提升是理解JS代码执行的关键概念。首先,作用域是指变量或函数可以在哪些区域中被访问的限制。JavaScript主要有两种作用域:全局作用域和函数作用域,而没有像C#、C、Java那样的块级...

    Linux 桌面玩家指南:19. 深入理解 JavaScript,及其开发调试工具 - 京山游侠 - 博客园1

    本文将深入探讨JavaScript的核心概念,包括对象和原型链、作用域链、上下文环境和闭包、函数和this、模拟面向对象编程、JavaScript的模块化写法,以及ECMAScript 6之后的新特性。 ### 对象和原型链 JavaScript的...

    600个javascript经典实例(内含源码)

    闭包是JavaScript的高级特性,能够访问和修改外部作用域的变量,常用于封装和模块化。 5. **面向对象编程**:JavaScript支持基于原型的面向对象编程,实例可能涉及构造函数、原型链、继承、封装和多态等概念。 6. ...

    深入理解JavaScript系列.chm

    14.作用域链(Scope Chain) 15.函数(Functions) 16.闭包(Closures) 17.面向对象编程之一般理论 18.面向对象编程之ECMAScript实现 19.求值策略 20.《你真懂JavaScript吗?》答案详解 21.S.O.L.I.D五大原则之接口...

    javascript常用技巧

    6. **闭包**:闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的常见方式是将函数作为其他函数的内部函数返回。 7. **异步编程**:JavaScript是非阻塞的,常用异步编程模型有回调函数、Promise、async/...

    全面解析Module模式1

    1. **模块化**:Module模式允许我们将相关的功能组织在一起,形成独立的模块,每个模块都有自己的作用域,不会与其他模块产生冲突。 2. **可重用**:由于模块内部的封装,我们可以多次引入和使用同一模块,而不用...

    全面解析JavaScript Module模式

    在JavaScript中,匿名函数可以自执行,这样就能立即执行代码并创建一个独立的作用域。 基础用法: 模块模式通常通过一个立即执行的匿名函数来实现。下面是一个简单的示例: ```javascript var Calculator = ...

    深入理解JavaScript系列(3) 全面解析Module模式

    Module模式利用了JavaScript的函数作用域和闭包特性,允许将私有变量和函数封装起来,仅对外提供一些接口进行操作。 在JavaScript编程中,我们经常会遇到需要组织和模块化代码的情况,以实现代码的高内聚低耦合。...

    JavaScript 面向对象之命名空间

    对象字面量可以让我们在全局作用域中定义一个对象,并通过点(.)操作符来访问该对象的属性,这些属性可以是其他对象或函数,从而形成一个层级结构的命名空间。 示例代码中的`RegisterNameSpace`函数就是用来注册...

    vue2制作自定义组件的教程

    在Vue2中,自定义组件是构建可复用和模块化应用的核心元素。自定义组件允许开发者将复杂的UI逻辑拆分成独立...同时,参考提供的链接资源,如CSDN博客和博客园的文章,可以进一步深入学习Vue组件的更多细节和进阶技巧。

    python入门到高级全栈工程师培训 第3期 附课件代码

    03 函数作用域补充 04 匿名函数 05 函数式编程介绍 06 函数式编程尾递归调用优化 07 map函数 08 map函数filter函数 09 reduce函数 10 map reduce filter总结 11 内置函数part1 第17章 01 课前吹牛 02 zip方法 03 ...

Global site tag (gtag.js) - Google Analytics