你不知道的JS系列 ( 9 ) - 函数表达式
在任意代码片段外部添加包装函数,可以将内部的变量和函数定义“隐藏”起来,外部作用域无法访问包装函数内部的任何内容。
var a = 2; function foo() { var a = 3; console.log(a); // 3 } foo(); console.log(a); // 2
虽然这种技术可以解决一些问题,但是会导致一些额外的问题。
1、foo 这个名称本身污染了所在作用域(在这个例子中是全局作用域)
2、必须显式地通过函数名调用才能运行
为了解决额外的问题,如果函数名不需要(或者至少函数名可以不污染所在作用域),并且能够自动运行,将会更加理想
var a = 2; (function foo(){ var a = 3; console.log(a); })() console.log(a);
比较一下两段代码,第一段 foo 被绑定在全局作用域中,通过 foo 来调用它。第二段 foo 被绑定在函数表达式自身的函数中,而不是所在的作用域。foo 变量名被隐藏在自身中不会污染外部作用域
如果 function 是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式
函数表达式最熟悉的场景可能就是回调参数了,比如
setTimeout(function(){ console.log('i wait 1 second') }, 1000)
这叫匿名函数表达式,函数表达式可以是匿名的,而函数声明则不可以省略函数名
很多库和工具也倾向鼓励使用这种风格的代码。但是它有几个缺点
1、匿名函数在栈追踪时不会显示有意义的函数名,使得调试很困难
2、一个函数需要引用自身的例子,在事件触发后事件监听器需要解绑自身,这时候做不了
3、匿名函数省略了代码可读性,一个描述性的名称可以让代码不言自明
行内函数表达式非常强大且有用-匿名和具名之间并不会对这点有任何影响,防止上述缺点,给出一个最佳实践
setTimeout(function timeoutHandler(){ console.log('i wait 1 second') }, 1000)