js执行环境的深入理解

第一个例子中 :之所以每个函数都返回不同的值的原因 有2点 (简写如下文)

就是[SCOPE]内部属性,函数可能拥有相同的父作用域时,多个函数引用同一个[SCOPE]属性,所以return i的值还是10(第一点),但是return num的值就不是了。因为每个内部函数的父执行环境都是新的(因为每次I++之后函数都会被调用执行每次进入的环境是新的)。所以多个函数不引用同一个[scope]属性,创建函数时[scope]中的作用域链中的所有父执行环境的A0/VO都是一个新的。当然全局父执行环境不是。因为它只被进入一次。(第二点)

function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){//创建函数时创建包含所有父执行环境的V0/AO对象指针作用域链,此链被保存在创建的函数的内部属性[[Scope]]中,第一次进入函数的执行环境,活动对象里的num属性值为0;第二次进入函数的执行环境,每次进入的函数的执行环境都是一个新的执行环境。很明显两次的执行环境是不同的。所以,此时活动里的num属性值为1;

return function(){//创建函数时创建包含所有父执行环境的V0/AO对象指针作用域链,此链被保存在创建的函数的内部属性[[Scope]]中,此时的num为0;当进入 result[0]()函数的执行环境时他的作用域链的第二个活动对象指针是父函数执行环境的活动对象 值为0;当进入 result[1]()第二次进入函数的新执行环境时,作用域链的第二个活动对象指针是父函数执行环境的活动对象,注意:此时的父函数的执行环境是一个新的执行环境,所以它的作用域链的第二个活动对象指针指向新的父函数执行环境的活动对象;还有一点当return函数退出时,父执行环境被销毁,但是活动对象依然保存在内存中(因为内部闭包匿名被引用中。);每个被保存到result数组里面的函数的执行环境的作用域链的第二个活动对象指针引用的都是一个新的父执行环境的活动对象;所以num值为1;这里之所以每个函数都返回不同的值的原因 有2点。一点是我之前说的一大堆,第二点就是[SCOPE]内部属性,函数可能拥有相同的父作用域时,多个函数引用同一个[SCOPE]属性,所以return i的值还是10,但是return num的值就不是了。因为每个内部函数的父执行环境都是新的。所以多个函数不引用同一个[scope]属性 ,创建函数时[scope]中的作用域链中的所有父执行环境的A0/VO都是一个新的。当然全局父执行环境不是。因为它只被进入一次。

return num;
};
}(i);//当循环体执行完毕后。result[i]里面的每个函数对象都是不相等的。
}
return result;
}

 

此例子的原因还是因为父执行环境相同不相同的问题。
function createFunctions(){ // 
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){// 创建函数时创建包含所有父执行环境的V0/AO对象指针作用域链,此链被保存在创建的函数的内部属性[[Scope]]中,
return i;
};
}
return result;//result[i]里面的每个函数对象都是不相等的。当循环体结束后createFunctions函数的执行环境的活动对象的属性i=10;父函数执行环境只被进入一次。 result[i]()每次进入函数执行环境都是一个新的执行环境。所有函数的执行环境的作用域链中的所有父执行环境的VO/AO对象指针是复制创建函数时的[Scope]属性中作用域链.循环语句中的多个函数可能拥有相同的父作用域时,多个函数引用同一个[SCOPE]属性,并且此属性中的作用域链的A0/VO是唯一的。因为父执行环境createFunctions只被进入一次,所以它的活动对象是唯一的.这就是为什么每个函数都返回10的原因;

}



function Person(name){
this.getName = function(){
return name;
};
this.setName = function (value) {
name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName()); //"Nicholas"
person.setName("Greg");
alert(person.getName()); //"Greg"
var persoe = new Person("icholas");
alert(persoe.getName());//这里弹出icholas是因为new的时候进入了新的函数的执行环境。而不是之前保存的执行环境 也就是说persoe.getName和person.getName的父执行环境不同。2个对象是不同的内存空间所以函数有2份。
alert(person.getName()); //"Greg" / /这里之所以会弹出greg是因为进行执行环境时,他的scope属性保存的作用域中的父执行环境中的VO对象指针是之前创建函数时的scope中的作用域链中的VO对象指针指向父执行环境中的VO对象。
说简单点就是2个对象的方法的执行环境的作用域链中的第二个活动对象指针指向的是不同的父执行环境的活动对象。


总结:如果想要让所有子执行环境引用同一个scpeo属性,只需要让父执行环境进入一次即可,这样子执行环境就拥有相同的父执行环境了。此环境的的vo/AO是唯一的。既然是唯一的,那么对此变VO/AO的属性做的想修改会反应到所有子执行环境。


如果想要让所有子执行环境引用不同的scpeo属性,只需要让父执行环境进入多次即可,这样子执行环境就不拥有相同的父执行环境了。不同的父执行环境的的vo/AO是不一样的。;既然是不一样的的,那么对此VO/AO的属性做的修改自然就反应到 和不同的执行环境相对应的子执行环境了。

还有一点就是:当父执行环境退出时,如果内部函数执行环境一直被引用状态,那么当再次进入此函数的执行环境时它的作用域链引用的是同一个SCOPE的地址,父执行环境的活动对象不会被销毁。还在内存中。 此链一直包含父执行环境的活动对象。
原文地址:https://www.cnblogs.com/qw26213/p/4846378.html