汤姆大叔的博客-note-函数
命名函数表达式的秘密
如果你想了解兼容性方面的东西的话,你还是应该继续往下
函数声明,它是程序的一部分
函数表达式:
命名函数表达式,他是赋值表达式的一部分
微妙的差别:
1.函数声明会在任何表达式被解析和求值之前先被解析和求值,即使你的声明在代码的最后一行,它也会在同作用域内第一个表达式之前被解析/求值
2.函数声明在条件语句内虽然可以用,但是没有被标准化,也就是说不同的环境可能有不同的执行结果,所以这样情况下,最好使用函数表达式
3.函数表达式则需要先声明,后使用
code:
function g (){ return [ arguments.callee == f, arguments.callee == g ] } var f = function(){ return [ arguments.callee == f, arguments.callee == g ] } //(特殊,不建议) var f = function g (){ return [ arguments.callee == f, arguments.callee == g ] }
自执行匿名函数
括号 ()是一个分组操作符,它的内部只能包含表达式
常见格式:(function() { /* code */ })();
解释:包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数。
作用:可以用它创建命名空间,只要把自己所有的代码都写在这个特殊的函数包装内,那么外部就不能访问,除非你允许(变量前加上window,这样该函数或变量就成为全局)。各JavaScript库的代码也基本是这种组织形式。
总结一下,执行函数的作用主要为 匿名 和 自动执行,代码在被解析时就已经在运行了。
//常见 (function(msg){ alert(msg) })() // 其他写法 (function () { /* code */ } ()); !function () { /* code */ } (); ~function () { /* code */ } (); -function () { /* code */ } (); +function () { /* code */ } ();
代码规范
1.首先防范标识符泄漏到外部作用域,其次,应该永远不引用被用作函数名称的标识符
2.关键就在于始终要通过f或者arguments.callee来引用函数
3.命名函数表达式会导致产生多余的函数对象,而该对象与返回的函数对象不是一回事
4.通过设置g为null,垃圾回收器就把g引用的那个隐式函数给回收掉了
5.开启严格模式的实现会禁用语言中的那些不稳定、不可靠和不安全的特性。
var fn = (function(){ // 声明要引用函数的变量 var f; // 有条件地创建命名函数 // 并将其引用赋值给f if (true) { f = function F(){ } } else if (false) { f = function F(){ } } else { f = function F(){ } } // 声明一个与函数名(标识符)对应的变量,并赋值为null // 这实际上是给相应标识符引用的函数对象作了一个标记, // 以便垃圾回收器知道可以回收它了 var F = null; // 返回根据条件定义的函数 return f; })(); var hasClassName = (function(){ // 定义私有变量 var cache = { }; // 使用函数声明 function hasClassName(element, className) { var _className = '(?:^|\\s+)' + className + '(?:\\s+|$)'; var re = cache[_className] || (cache[_className] = new RegExp(_className)); return re.test(element.className); } // 返回函数 return hasClassName; })();
在web开发中有个常用的模式是基于对某种特性的测试来伪装函数定义,从而达到性能优化的目的,但由于这种方式都是在同一作用域内,所以基本上一定要用函数表达式