函数作用域
属于这个函数的全部变量都可以在整个函数的范围内使用及复用。
从两个角度来理解 函数作用域 的意义和用途:外部和内部。
“外部”指的是,声明一个函数,往里面添加代码。
可以理解为添加一个工具函数。
“内部”指的是,将需要私有化的变量和逻辑封装进一个函数中,相当于用一个函数作用域去隐藏内部。
制作一个工具函数
比如我们需要一个能将 name-age 转换为 nameAge 的工具函数。
那这时候我们会声明一个函数,命名为 transUpper。
function transUpper(str) {
// ... 往这里添加 name-age 转 nameAge 的逻辑
}
此时我们以 transUpper 创建了一个函数作用域,内部声明的一切变量将为内部逻辑所使用。
外部无法访问这个函数内部的变量。
最小特权原则
来看下面这段代码,找找看有什么很膈应的地方?😏
function fn(a) {
b = a + foo(a * 2);
console.log(b * 3);
}
function foo(a) {
return a - 1;
}
var b;
fn(2);
可以看到,foo 和 b 都挂到了全局作用域下了。
但使用的地点却在 fn 中。
可见如此设计代码结构并不合理。
改成如下方式:
function fn(a) {
function foo(a) {
return a - 1;
}
var b = a + foo(a * 2);
console.log(b * 3);
}
fn(2);
规范许多。
在这个 case 中,其实我们利用了函数作用域的特性,将变量 b 和函数 foo 隐藏到 fn 的作用域内部,避免了污染全局作用域。
规避冲突
接上,我们知道如果把变量都定义在全局作用域中的话,会很容易造成命名冲突。
在规避冲突的方面,函数作用域也能发挥很好的作用。
有一个很经典的case。
来看下面这段代码:
function foo(){
function bar(a) {
i = 3; // 这里有问题
console.log(a + i);
}
for(var i=0; i<10; i++) {
bar(i * 2);
}
}
foo();
可以先思考一下这段代码会有什么样的执行结果,和预期的效果是否一致。
输出结果是无限循环打印11。
这里为啥会无限循环打印呢?
原因在于i = 3这一行上。
每一次在循环体中调用 bar 函数的时候,bar 函数内部的变量 i 会覆盖循环体中的 i,导致 i 的值永远为 3,也永远满足不了i>=10的条件,便造成了无限循环的后果。
想要达到预期效果,需要改成如下:
function foo(){
function bar(a) {
var i = 3; // 修改这里
console.log(a + i);
}
for(var i=0; i<10; i++) {
bar(i * 2);
}
}
foo();
小结
今天主要从两个不同的角度来介绍函数作用域,主要在于如何深入理解函数作用域、利用函数作用域的特性能做什么等等。
明天继续!GoodBye~