在js高程中,闭包是指有权访问另一个函数作用域中的变量的函数。
function createComparisonFunction(propertyName){ function compare(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } }; }
上例所述的compare()函数就是闭包。
在js中每个执行环境都有一个表示变量的对象(变量对象)。全局环境的变量对象始终存在,而像createComparisonFunction()函数这样的局部变量的变量对象,则只在函数执行的过程中存在。在创建createComparisonFunction()函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。
当调用createComparisonFunction()函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性的对象,构建起执行环境的作用域链。此后,又有一个活动对象(注:createComparisonFunction()函数的活动对象指的是包含arguments、propertyName、compare的变量对象),被创建并推入执行环境作用域链的前端(注:在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部哈数的活动对象处于第三位...直到作为作用域链终点的全局执行环境,作用域链只能向上搜索。)。
对于createComparisonFunction()函数的执行环境而言,其作用域链中包含两个变量对象:本地活动对象和全局变量对象。作用域本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
一般来说,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。但是闭包的情况又有所不同。
在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中,即内部函数的作用域包含外部函数的变量对象。因此compare()函数可以访问createComparisonFunction()函数中定义的所有变量,更重要的是外部函数(createComparisonFunction()函数)在执行完之后,其活动对象也不会被销毁,因为内部函数(compare()函数)的作用域链仍然在引用这个活动对象。也就是说,外部函数执行完后,其执行环境的作用域被销毁但是它的活动对象仍然会留在内存中,直到内部函数被销毁,其活动对象才会被销毁。
注:
(1)执行环境:执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
(2)闭包会携带包含它的函数的作用域,因此会比其他函数占更多的内存。