第三章 函数作用域和块作用域
函数中的作用域
函数作用域的含义是指,属于这个函数的全部变量都可以在整个函数的范围内使用及复用(事实上在嵌套的作用域中也可以使用)。
隐藏内部实现
最小特权原则
也叫最小授权或最小暴露原则。这个原则是指在软件设计中,应该最小限度地暴露必要内容,而将其他内容都“隐藏”起来,比如某个模块或对象的API设计。
规避冲突
“隐藏”作用域中的变量和函数所带来的另一个好处,是可以避免同名标识符之间的冲突,两个标识符可能具有相同的名字但用途却不一样,无意间可能造成命名冲突。冲突会导致变量的值被意外覆盖。
避免冲突的方法?
- 全局命名空间 一些库通常会在全局作用域中声明一个名字足够独特的变量,通常是一个对象。这个对象被用作库的命名空间 ,所有需要暴露给外界的功能都会成为这个对象(命名空间)的属性,而不是将自己的标识符暴漏在顶级的词法作用域中。
- 模块管理(es6模块化,CommonJs)
如何区分函数声明和函数表达式?
function在声明中出现的位置(不仅仅是一行代码,而是整个声明中的位置)如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。
var a = 2;
function foo() { // <-- 添加这一行
var a = 3;
console.log( a ); // 3
} // <-- 以及这一行
foo(); // <-- 以及这一行
console.log( a ); // 2
var a = 2;
(function foo(){ // <-- 添加这一行
var a = 3;
console.log( a ); // 3
})(); // <-- 以及这一行
console.log( a ); // 2
比较一下前面两个代码片段。第一个片段中foo被绑定在所在作用域中,可以直接通过foo()来调用它。第二个片段中foo被绑定在函数表达式自身的函数中而不是所在作用域中。
换句话说,(function foo(){ .. })作为函数表达式意味着foo只能在..所代表的位置中被访问,外部作用域则不行。foo变量名被隐藏在自身中意味着不会非必
函数声明和函数表达式之间最重要的区别是它们的名称标识符将会绑定在何处。
匿名和具名函数
没有名称标识符的函数叫做匿名函数
::函数表达式可以是匿名的,而函数声明不可以忽略函数名(忽略是非法的::
匿名函数的缺点
- 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难。
- 如果没有函数名,当函数需要引用自身时只能使用已经
arguments.callee引用,比如在递归中。另一个函数需要引用自身的子的例子,是在事件触发后事件监听器需要解绑自身。 - 匿名函数省略了对于代码可读性/可理解性很重要的函数名。一个描述性的名称可以让代码不言自明。
::始终给函数表达式命名是一个最佳实践::
立即执行函数
IIFE,代表立即执行函数表达式(Immediately Invoked Function Expression)
IIFE的一个非常普遍的进阶用法是把它们当作函数调用并传递参数进去。
“var a = 2;
(function IIFE( global ) {
var a = 3;
console.log( a ); // 3
console.log( global.a ); // 2
})( window );
console.log( a ); // 2
块作用域
- let
- count
- try/catch