网站优化

慈溪微信小程序开发_JavaScript作用域链实例详解

作者:admin 发布时间:2021-01-08
JavaScript作用域链实例详解       这篇文章主要介绍了JavaScript作用域链,结合实例形式较为详细的分析了作用域链的原理、功能与相关操作注意事项,需要的朋友可以参考下

本文实例讲述了JavaScript作用域链。分享给大家供大家参考,具体如下:

跟其他语言一样,变量和函数的作用域揭示了这些变量和函数的搜索路径。对于JavaScript而言,理解作用域更加重要,因为在JavaScript中,作用域可以用来确定this的值,并且JavaScript有闭包,闭包是可以访问外部环境的作用域的。
每一个JavaScript的函数都是Function对象的一个实例,Function对象有一个内部属性[[Scope]],这个属性只能被JavaScript的引擎访问。通过[[Scope]]属性可以访问函数的作用域链,从而可以搜索变量和函数,判断变量和函数位于作用域链中的哪一个活动对象中。

简单的作用域链

当一个函数被创建的时候,因为函数是Function对象的一个实例,因此也会有[[Scope]]这个内部属性,Scope属性指向一个作用域链,作用域链中默认至少包含一个全局对象变量。

pare(value1, value2){
 if (value1 value2) {
 return -1;
 } else if (value1 value2) {
 return 1;
 } else {
 return 0;
var result = compare(5, 10);

当compare()函数在全局作用域中被调用执行的时候,JavaScript引擎会创建一个运行时上下文(execution context)的内部对象,一个运行时上下文定义了一个函数执行时的环境。函数诶次执行时的运行时上下文都是不同的,因此多次调用就会导致多个运行时上下文的创建与销毁。

每个运行时上下文都有自己的作用域链,用于变量和函数这些标识符的解析。

运行时上下文在函数调用执行时被创建,在函数执行完毕的时候被销毁。在运行时上下文创建的时候,首先会复制该被调用函数的[[Scope]]属性中的对象,然后一个活动对象(作为变量对象使用)pare()pare()的活动对象(activation pare())与全局变量对象(global object)。

对于简单的作用域链,就是这样了,但是有闭包的情况会有所不同。

闭包的作用域链

//step1: define createComparisonFunction
function createComparisonFunction(propertyName){
 return function(object1, object2){
 var value1 = object1[propertyName];
 var value2 = object2[propertyName];
 if (value1 value2) {
 return -1;
 } else if (value1 value2) {
 return 1;
 } else {
 return 0;
//step2: call createComparisonFunction
pare = createComparisonFunction("name");
//step3: pare
var result = compare({name: "Nicholas"}, {name: "Gerg"});
//step4: dereference closure for recycle memory
compare = null;

我们分下列几个步骤来图解作用域链:

step1: 定义createComparisonFunction;

在创建createComparisonFunction函数之后,createComparisonFunction可以被调用了,因此一个createComparisonFunction的Function对象被保留下来;
此时内存中保留对象:

1. Global Object

2. createComparisonFunction对象 Scope Chain

step2: 执行createComparisonFunction;

在执行createComparisonFunction的过程中,首先会创建createComparisonFunction的运行时上下文对象 + ScopeChain + 活动对象,其次会创建一个闭包(匿名函数),
函数执行时内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. createComparisonFunction的运行时上下文对象 + Scope Chain
4. createComparisonFunction的活动对象
5. Closure(anonymous)的Function对象 + Scope Chain

在执行完createComparisonFunction之后,createComparisonFunction的运行时上下文对象+ScopeChain会被销毁,但是createComparisonFunction的活动对象因为被Closure(anonymous)对象的ScopeChain所引用,因此不会被销毁。

函数执行完内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象

对比step1, step2在执行完之后,增加了两个对象:

1. Closure(anonymous)的Function对象 + Scope Chain
2. createComparisonFunction的活动对象

step3: 执行compare;

闭包执行时内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. 闭包Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象
5. 闭包Closure(anonymous)的运行时上下文 + Scope Chain
6. 闭包Closure(anonymous)的活动对象

执行完闭包Closure(anonymous)之后,闭包Closure(anonymous)的活动对象会被销毁,闭包Closure(anonymous)的运行时上下文 + Scope Chain也会被销毁。

闭包执行完内存中保留对象:

1. Global Object
2. createComparisonFunction的Function对象 + Scope Chain
3. 闭包Closure(anonymous)的Function对象 + Scope Chain
4. createComparisonFunction的活动对象

对比step2,step3执行完毕之后,内存中保留的对象没有增加,这就是正常执行一个函数的情况。

在正常情况下,执行完一个函数之后,内存中保留的对象应该与执行前一样的。

执行闭包因为没有引入新的引用,所以内存中保留的对象保持了一致。

那么问题来了,createComparisonFunction的活动对象到底怎么才能被销毁呢?

我们首先看createComparisonFunction的活动对象存在的原因是闭包Closure(anonymous)的Function对象的Scope Chain引用了createComparisonFunction的活动对象,其目的是因为闭包中需要访问propertyName这个createComparisonFunction的活动对象中的属性。

如果闭包Closure(anonymous)的Function对象被销毁之后,createComparisonFunction的活动对象因为没有被任何对象引用,也会被销毁。

使用闭包的问题就是内存消耗会比一般的函数大,因为要保存额外的活动对象,所以在不需要使用闭包的时候,需要将闭包解引用,回收额外的活动对象所占用的内存。

执行完step4之后内存中保留的对象:

1. Global Object

2. createComparisonFunction的Function对象 + Scope Chain

对比step1,step4在执行完毕之后,没有额外的对象被保留在内存中,引用闭包所产生的额外对象都得到了回收。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《》、《》、《》、《》及《》

希望本文所述对大家JavaScript程序设计有所帮助。



收缩