标签:com 索引 开始 属性 loading 预处理 声明 指针 进入
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式是在一个函数中创建另一个函数
创建一个预先包含全局环境变量对象的作用域链,这个作用域链被保存在函数内部的[[scope]]属性中。
函数被调用,即执行流进入函数中
如上例所示,作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。在函数中访问变量时,会从作用域链中从本地活动变量一直搜索到全局变量对象。函数执行完毕后,局部活动对象被销毁,内存中仅保存全局执行环境和它的变量对象。
function outer(propertyAge) {
return function (obj1, obj2) {
var val1 = obj1[propertyAge];
var val2 = obj2[propertyAge];
if (val1 > val2) {
console.log(`${obj1.name}比较大`);
} else if (val1 < val2) {
console.log(`${obj2.name}比较大`);
} else {
console.log(`${obj1.name}与${obj2.name}一样大`);
}
}
}
var person1 = {
name: ‘Nick‘,
age: 27
};
var person2 = {
name: ‘Jane‘,
age: 25
};
var compare = outer(‘age‘);
compare(person1, person2); //‘Nick比较大‘
从头开始捋:
1 创建outer函数时,将全局作用域的作用域链(即全局执行环境下的变量对象的指针)的副本加入到函数的内部的[[scope]]属性中。
2 调用outer函数,为outer函数创建一个执行环境,创建作用域链,复制函数内部的[[scope]]属性的变量对象的指针,把它塞进作用域链。
3 将outer函数的arguments对象和其它命名参数的值初始化为活动变量,作为当前局部作用域的变量对象,并把它塞进作用域链的前端。(此时的outer函数的作用域链拥有本地活动对象和全局变量对象的指针)
4 执行outer函数完毕,将内部匿名函数返回给全局变量compare。执行流进入到outer函数内时便会对局部作用域执行预处理(js预处理不会进入到函数内部,全局作用域预处理阶段outer函数连局部作用域都没有创建,当代码执行流进入到outer函数内部后才会创建匿名函数),内部函数因为函数声明提升会被直接创建(执行流进入到outer函数中时,匿名函数就被创建了)。执行创建函数的流程————将外部作用域的作用域链的副本存入到自己的[[scope]]属性中去。执行return语句后执行流会直接跳出当前作用域,outer函数已经完成使命,其作用域被直接销毁,作用域中保存的作用域链也会被直接被销毁。
5 outer函数的作用域和作用域链虽然被销毁了,但是对outer函数作用域链中保存的全局变量对象和outer函数本地活动对象的引用被复制保存到匿名函数中了(这些变量对象和活动对象被完好地保存在堆内存中,销毁的只是outer函数作用域链对它们的引用的指针),对于对象而言,只要引用存在就不会被销毁。
6 调用匿名函数,创建匿名函数的作用域,创建该作用域的作用域链,将[[scope]]属性中的作用域链副本塞进作用域链,使用arguments对象和其它命名参数的值初始化本地活动对象,并将本地活动对象视为变量对象,塞进匿名函数作用域链的最前端。此时的匿名函数作用域链按索引优先级包括了本地活动对象,outer函数的活动对象,全局变量对象。也因此匿名函数可以访问到在outer函数和全局作用域中定义的变量,函数以及参数。完成闭包操作。
标签:com 索引 开始 属性 loading 预处理 声明 指针 进入
原文地址:https://www.cnblogs.com/Syinho/p/13229451.html