匿名函数的基本形式为<代码>(函数(){…})();代码>
前面的括号包含函数体,后面的括号就是给匿名函数传递参数并立即执行之
匿名函数的作用是避免全局变量的污染以及函数名的冲突
无论你在什么时候读代码,您都必须注意到匿名函数。有时它们被称为λ,有时是匿名函数,不管怎样,我认为他们是不好使用的。
如果你不知道匿名函数是什么,这里有一个引语:
匿名函数是一种在运行时动态声明的函数。它们之所以被称为匿名函数是因为不同于普通函数,它们并没有函数名。——海伦·爱默生Helephant.com
匿名函数形式如下:
函数(){…代码…} 或 (args)=比;{…代码. .}
我今天尝试让大家理解通常情况下只有在绝对需要的情况下才使用匿名函数的想法。匿名函数不应该是首选,而且应该知道原因情况下使用。当理解这种想法之后,你的代码会变得更简洁,更容易维护,并且更容易跟踪bug。先从避免使用匿名函数的三个理由开始:
你写代码的时候,无论你多么擅长敲代码,总是会碰到错误。有时候,这些错误很容易被查出,有时候并不容易。
如果你知道这些错误来自哪里,那么错误很容易会被查出来。为了查出错误,我们使用这个被叫做堆栈轨迹的工具。如果你不了解堆栈轨迹,古耳给出了很棒的介绍。
假设现在有一个非常简单的工程:
函数开始(){ (中间函数(){ (函数结束(){ console.lg(测试); })() })() }
上面代码里面有一个非常愚蠢的错误,拼写错误(console.log)。在小工程里面,这个拼写错误不是什么大问题。如果这是一个有非常多模块非常大的工程的一小段,问题就大了。假设这个愚蠢的错误不是你犯的,那么新来的初级工程师将会在他休假之前把这个错误提交到代码库!
现在,我们必须追查。使用我们精心命名的函数,我们得到如下的堆栈跟踪:
谢谢你命名你的函数,初级开发者们!现在我们可以轻松地追踪到这个bug。
但是. .一旦我们解决了这个问题,就会发现还有另一个错误。这次是一位更资深的开发人员介绍的。这个人知道λ
结果他们偶然发现了一个错误,我们的工作就是追踪它。
下面是代码:
(函数(){ (函数(){ (函数(){ console.lg(测试); }) (); }) (); })();
吃不吃惊,这名开发者也忘记了如何拼写console.log了!这也太巧合了吧!令人感到遗憾的是,他们都没有命名他们的函数。
那么控制台会输出什么呢?
好吧,我们至少还有行号,对吧?在这个例子中,看起来我们有大约7行代码。如果我们处理一大段代码会如何呢?比如一万行代码?行号的跨度如此之大该怎么办呢?如果代码被折叠后有没有一个代码地图文件,那么对行号的渲染是不是根本就是没有什么用了呢?
我想对这些问题的回答相当简单,答案就是:想这些会让你一整天都会过的相当糟心。
咦,我听说你还不信。你仍旧对你的匿名函数恋恋不舍,并且还从未发生过错误。那么我得向你道的歉,你认为你的代码是完美的。让我们看看这个!
看看下面两段代码:
函数初始化(参数){ 返回新的承诺((解决,拒绝)=比;{ 尝试{ 如果(参数){ 返回解决(真正的); } 返回解决(假); }捕捉(e) { 拒绝(e); } }); } 启动(真正的) 不要犹豫(res=比;{ 如果(res) { doSomethingElse (); 其他}{ doSomething (); } )。抓住(e=比;{ logError (e.message); restartApp (); });
这是一个非常不正常的例子,但是我相信你已经明白我要说什么了。我们的方法返回了一个承诺,我们用这个承诺对象/方法处理不同可能的响应。
你也许会认为几段代码读起来并不难,但我认为它们可以变得更好!
如果我们去掉所有的匿名函数会怎样呢?
函数初始化(参数){ 返回新的承诺(checkForArguments); } 函数checkForArguments(解决,拒绝){ 尝试{ 如果(参数){ 返回解决(真正的); } 返回解决(假); }捕捉(e) { 拒绝(e); } } 函数evaluateRes (res) { 如果(res) { doSomethingElse (); 其他}{ doSomething (); } } 函数handleError (e) { logError (e.message); restartApp (); } 启动(真正的) 不要犹豫(evaluateRes) .catch (handleError);不使用JS匿名函数理由