浅谈javascript函数执行过程

Posted 我不是一个人在战斗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈javascript函数执行过程相关的知识,希望对你有一定的参考价值。

javascript函数执行过程:

  1. 为函数创建一个执行环境

  2. 复制函数的 [[scopes]] 属性中的对象构建起执行环境的作用链域

  3. 创建函数活动对象并推入执行环境作用链域的前端

  4. 执行代码

  5. 销毁执行环境和活动对象(闭包情况下活动对象仍被引用没被销毁)

 

用例子来说明:

function Person(name) {
    this.getName = function() {
        return name;
    };

    this.setName = function(value) {
        name = value;
    };
}

var person = new Person("Candy");
alert(person.getName()); //"Candy"
person.setName("Greg");
alert(person.getName()); //"Greg"

 

以调用Person()构造函数、setName() 函数为例,函数执行过程中,各对象的关系如下:

(1)未调用前,只存在全局变量对象

  全局变量中定义了Person() 构造函数,Person作为全局变量对象的一个属性,[[scopes]] 保存着Person() 构造函数的作用链域,因为Person() 构造函数是定义在全局变量对象里面的

  Person为什么会有 [[scopes]] 属性???

  在创建函数时,会创建一个预先包含全局变量对象的作用链域,这个作用链域被保存在内部的 [[scopes]] 属性中

(2)new Person() 创建对象,调用之后,存在全局变量对象,Person对象

  用new调用构造函数会经过以下4个步骤:

    1. 创建一个新对象

    2. 将构造函数的作用域赋给新对象(因此this就指向这个新对象——person,这也是变量name为什么不是对象属性的原因)

    3. 执行构造函数中的代码(为新对象添加属性)

    4. 返回新对象

  重点说第3个过程,执行过程如图:

调用(执行)函数时,会为函数创建一个执行环境,然后通过复制函数的 [[scopes]] 属性中的对象构建起执行环境的作用链域。此后,又有一个活动对象(Person的活动对象)被创建并推入执行环境作用链域的前端,所以图中的作用链域有2层。

  调用完毕后,返回Person对象

Person执行环境在函数执行完毕后销毁,Person活动对象没有被销毁

  为什么Person活动对象没有被销毁???

    这种情况属于闭包:Person活动对象仍然被getName、setName的 [[scopes]] 引用,即仍在作用链域中,所以没有被销毁

  注意:

    Person() 构造函数中定义了getName()、setName() 两个函数,还有函数的参数name

    new Person() 创建的 Person对象 的属性只有getName()、setName(),没有name属性,name不是用this声明的,不是Person对象的属性

     

(3)调用setName(),存在全局变量对象,Person对象

 

 创建setName() 的执行环境,然后通过复制函数的 [[scopes]] 属性中的对象构建起执行环境的作用链域。此后,又有一个活动对象(setName的活动对象)被创建并推入执行环境作用链域的前端,所以图中的作用链域有3层。

 函数执行完毕后:

 

 

setName执行环境和setName活动对象都被销毁,因为setName活动对象没有被引用

 

- 其他:

通过这个例子,也很好理解为什么person.name是undefined,因为person对象没有name这个属性,getName、setName能访问name属性是因为它们通过作用链域访问到了Person活动对象中的name属性

 

PS:用构造函数创建的对象是独立的

 

以上是关于浅谈javascript函数执行过程的主要内容,如果未能解决你的问题,请参考以下文章

浅谈JavaScript中的异步处理

浅谈JS的作用域链

浅谈JavaScript预编译原理

浅谈js回调函数

浅谈JavaScript词法分析步骤

浅谈JavaScript词法分析步骤