文档章节

JavaScript执行环境

小微
 小微
发布于 2012/08/30 19:16
字数 2207
阅读 169
收藏 5

今天的一个小程序有点问题,后来发现是因为对JavaScript执行环境理解不到位所造成的,因此转载整理了两篇讲的不错的文章分享在这里。

文章来源1:理解javascript执行环境

执行环境可以理解为一个栈,而全局变量——一切Js在其中发生,可以理解为栈底或者是一个装载其他子执行环境的容器。

函数执行是会在其自己的执行环境中执行,递归调用中,每一次递归调用都会有新的执行环境。当调用完成后,函数会返回原始的执行环境。

调用函数时,函数的执行环境的创建过程:

1. 在函数的执行环境中,创造一个活动对象(没有预定义原型的对象,且不可直接引用)

2. 创建一个arguments对象,这个对象类似数组,拥有length,callee等属性。arguments以整数下标的形式保存实际传入函数的参数。length对应实际传入参数的个数。

3. 为活动对象创建arguments属性,指向创建好的arguments对象

4. 为执行环境分配作用域,每个函数内部的[[scope]]属性由对象列表(链)组成,这个[[scope]]会被指定给一个函数调用执行环境,作为其作用域,同时把活动对象被添加到执行环境[[scope]]的前端

5. “可变对象”(这时的可变对象就是活动对象)完成“对象实例化”创建可变命名参数,依照函数定义的形式参数。接收实际参数,没有获得实际参数的可变命名参数被置为undefined

6. 对于内部声明的函数,在执行环境中创建新的函数对象,然后创建函数名属性(指针)指向新创建的内部函数对象。并将在函数内部声明的所有局部变量创建为可变对象的命名属性。根据声明的局部变量创建的可变对象的属性在变量实例化过程中会被赋予 undefined值。在执行函数体内的代码、并计算相应的赋值表达式之前不会对局部变量执行真正的实例化。事实上,拥有 arguments 属性的活动对象和拥有与函数局部变量对应的命名属性的可变对象是同一个对象。因此,可以将标识符 arguments 作为函数的局部变量来看待

7. 为this关键字赋值

如果this指向一个对象的引用(比如对象的方法),则this就是引用该对象的属性。

如果赋值为null,则this指向全局变量(Js设计时的一个bug)

文章来源2: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”,再次访问就不会有问题.

注:文中有一段中讲到"一般来讲",那在什么时候又不满足情况了?这个就由接下来的文章解答吧!

© 著作权归作者所有

小微
粉丝 117
博文 78
码字总数 81696
作品 0
海淀
程序员
私信 提问
[JavaScript]-JavaScript的this原理.

一、问题的由来 学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。 上面代码中,虽然obj.foo和foo指向同一个函数,但是执行结果可能不一样。请看下面的例子。 这种...

xiaoLoo
2018/06/27
225
1
从本质上理解JavaScript中的变量提升

JavaScript中奇怪的一点是你可以在变量和函数声明之前使用它们。就好像是变量声明和函数声明被提升了代码的顶部一样。 然而JavaScript并不会移动你的代码,所以JavaScript中“变量提升”并不...

我听莫扎特
07/23
0
0
JavaScript 执行机制-浏览器事件循环

大多数时候,我们去面试,都会遇到,让你说出一段代码的执行结果,或者说出其执行顺序。因为javascript是单线程的。 关于javascript javascript 是一门单线程语言,最新的H5中提出了webwork...

legendaryedu
04/04
0
0
JavaScript的宏任务与微任务

在介绍前端宏任务与微任务之前,先列出来一道题,一块看一下。 诸位可以先给出来一个自己的答案,运行一下结果,看看是否与自己想的一致。 1.基本概念 这里介绍一下JavaScript里面的一些基本...

公子穷奇
04/08
0
0
【译】理解JavaScript闭包——新手指南

闭包是JavaScript中一个基本的概念,每个JavaScript开发者都应该知道和理解的。然而,很多新手JavaScript开发者对这个概念还是很困惑的。 正确理解闭包可以帮助你写出更好、更高效、简洁的代...

LINJIAJUN
2018/11/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

postman批量测试

postman批量调用: 先单个调用,成功了 再save为collection 再点击三角形,点击run 设置1000次,run就可以 见《postman批量测试.docx》

Danni3
31分钟前
8
0
js 对象操作 js 对象和对象赋值 去除关联性 对象原型操作 把一个对象A赋值给另一个对象B 并且对象B 修改 不会影响 A对象

当我们在项目需要 复制一个对象到另一个对象并且 被复制的对象不能受复制后的对象的影响。 我先总结下 我们哪些方法可以复制对象 // 直接赋值var obj1 = { a: 1 };var obj2 = obj1;...

xiaogg
32分钟前
7
0
Go微服务全链路跟踪详解

在微服务架构中,调用链是漫长而复杂的,要了解其中的每个环节及其性能,你需要全链路跟踪。 它的原理很简单,你可以在每个请求开始时生成一个唯一的ID,并将其传递到整个调用链。 该ID称为C...

倚天码农
46分钟前
6
0
QML笔记-对QML中信号与槽的基本认识

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq78442761/article/details/90753986 目录 基本概念 演示...

shzwork
53分钟前
5
0
SSH安全加强两步走

从 OpenSSH 6.2 开始已经支持 SSH 多因素认证,本文就来讲讲如何在 OpenSSH 下启用该特性。 OpenSSH 6.2 以后的版本多了一个配置项 AuthenticationMethods。该配置项可以让 OpenSSH 同时指定...

xiangyunyan
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部