JS函数:变量作用域
变量作用域,闭包
我们已经知道函数可以访问其外部的变量。
但是,如果在函数内部创建一个与外部同名的变量之后,外部变量发生了变化会怎样?函数会获得新值还是旧值?
代码块
如果在代码块 {...} 内声明了一个变量,那么这个变量只在该代码块内可见。
例如:
<script> { // 使用在代码块外不可见的局部变量做一些工作 let message = "Hello"; // 只在此代码块内可见 alert(message); // Hello } alert(message); // 错误: message is not defined </script>
我们可以使用它来隔离一段代码,该段代码执行自己的任务,并使用仅属于自己的变量:
{ // 显示 message let message = "Hello"; alert(message); } { // 显示另一个 message let message = "Goodbye"; alert(message); }
很正常,各显示各的,互不干扰,但是这里没有代码块的话会报错:
// 显示 message let message = "Hello"; alert(message); // 显示另一个 message let message = "Goodbye"; // 错误: variable already declared alert(message);
这里将会提示 let 对已存在的变量进行重复声明。
对于 if,for 和 while 等,在 {...} 中声明的变量也仅在内部可见:
if (true) { let phrase = "Hello!"; alert(phrase); // Hello! } alert(phrase); // Error, no such variable!
所以,我们现在知道了,只要是在{...}里面的,就只对花括号里面生效。每个{...}里面定义的变量,在这个代码段执行完成后,内部的变量就会被系统释放掉,将不复存在。
嵌套函数
当一个函数是在另一个函数中创建的时,那么该函数就被称为“嵌套”的。
function sayHiBye(firstName, lastName) { // 辅助嵌套函数使用如下 function getFullName() { return firstName + " " + lastName; } alert( "Hello, " + getFullName() ); alert( "Bye, " + getFullName() ); }
嵌套函数:作为一个新对象的属性或作为结果返回。之后可以在其他地方使用。不论在哪里调用,它仍然可以访问相同的外部变量。
下面的 makeCounter 创建了一个 “counter” 函数,该函数在每次调用时返回下一个数字:
function makeCounter() { let count = 0; return function() { return count++; }; } let counter = makeCounter(); alert( counter() ); // 0 alert( counter() ); // 1 alert( counter() ); // 2
闭包
闭包 是指内部函数总是可以访问其所在的外部函数中声明的变量和参数,即使在其外部函数被返回(寿命终结)了之后。在某些编程语言中,这是不可能的,或者应该以特殊的方式编写函数来实现。但是如上所述,在 JavaScript 中,所有函数都是天生闭包的(只有一个例外,将在 "new Function" 语法 中讲到)。
也就是说:JavaScript 中的函数会自动通过隐藏的 [[Environment]] 属性记住创建它们的位置,所以它们都可以访问外部变量。
在面试时,前端开发者通常会被问到“什么是闭包?”,正确的回答应该是闭包的定义,并解释清楚为什么 JavaScript 中的所有函数都是闭包的,以及可能的关于 [[Environment]] 属性和词法环境原理的技术细节。