javascript函数执行过程:javascript
1. 为函数建立一个执行环境前端
2. 复制函数的 [[scopes]] 属性中的对象构建起执行环境的做用链域java
3. 建立函数活动对象并推入执行环境做用链域的前端闭包
4. 执行代码函数
5. 销毁执行环境和活动对象(闭包状况下活动对象仍被引用没被销毁)this
用例子来讲明:spa
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)未调用前,只存在全局变量对象blog
全局变量中定义了Person() 构造函数,Person做为全局变量对象的一个属性,[[scopes]] 保存着Person() 构造函数的做用链域,由于Person() 构造函数是定义在全局变量对象里面的ip
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:用构造函数建立的对象是独立的