第七章函数表达式- 闭包章节读书笔记记录。(P178开始闭包--
闭包:闭包是指有权访问另一个函数作用域中的变量的函数, 即闭包的本质是函数。
首先先复习下JavaScript中的作用域相关的知识点。
JavaScript的作用域分为全局和局部(函数),
ES6前的JavaScript没有块级作用域,所以会导致理解上的困惑,如:
if (true) { var color = 'blue'; } alert(color); // 输出 blue
如果是C/C++/Java类似的语言中,color会在if执行完毕后被销毁,但在JavaScript中,if语句中的变量声明会将变量添加到当前的执行环境中(当前执行环境级全局环境),所以alert(color)不会报错,输出blue值。
在使用for语句的时候尤其要牢记改点差异,如:
for(var i =0; i< 10; i++) { doSomething(i); } alert(i); // 输出10;
在有块级作用域的语言中,for语句初始化变量的表达式所定义的变量,只会存在于循环的环境中。而对于JavaScript来说,不存在块级作用域,变量i由于变量声明会将变量添加到当前的执行环境中(当前为全局),所以在for循环结束后,变量i未被销毁,一直存在外部的执行环境中,所以会输出10.
声明变量;
使用var声明的变量会自动添加到最近的执行环境中,在函数内部,最近的环境就是函数的局部环境中,如果变量没有被var声明,该变量会自动添加到全局环境中,如:
function add(num1, num2) { var sum = num1 + num2; return sum; } var result =add(1, 2); console.log(sum); // 提示报错
由于sum通过var 进行声明,所以sum存在的作用域为局部作用域,仅在函数内部使用,所以在函数外部调用变量sum,由于外部中不存在sum变量,所以会报错。如果sum未通过var进行声明,则在外部访问该变量不会报错,如:
function add(num1, num2) { sum = num1 + num2; return sum; } var result = add(1, 2); console.log(sum); // 输出3
由于sum未通过var进行声明,所以被添加到全局环境中,所以在add()执行完,sum变量仍存在,所以访问该变量不会报错。
当某个函数在调用的时候,会创建一个执行环境以及相应的作用域链。然后使用arguments和其他命名参数的值来初始化函数的活动对象,但在作用域链中,外部函数的活动对象始终处在第二位,外部行数的外部函数的活动对象处于第三位,...直至作为作用域链终点的全局执行环境。在函数执行过程中,为读取和写入变量的值,就需要在作用域链中查找变量。如:
function compare(value1, value2) { if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } } var result = compare(5, 10);
注: 由于闭包会携带包含它的函数作用域,因此会比其他函数占用更多的内存,过度使用闭包,可能会导致内存占用过多。
匿名函数的执行环境具有全局性,所以其this对象通常执行window,当然通过call()或apply()改变函数执行环境的情况下,this就会指向其他对象。