『翻译』3个缘由让我像躲避瘟疫同样避免使用JS匿名函数

Read the originaljavascript


前言

不管什么时候阅读代码,你必定会看到匿名函数。有时它们被称为lambdas,有时被称为匿名函数(anonymous functions),但无论怎样,我认为他们是糟糕的。java

若是你不知道什么是匿名函数,这里有一段引用:git

匿名函数是一个能够在运行时动态声明的函数。之因此称为匿名函数是由于:他们没有像普通函数同样被赋予名字(name)。 ——Helen Emerson, Helephant.comgithub

它们看起来有点像这个:web

function() { ... code ... }

OR

(args) => { ... code ... }复制代码

下面我会举一些例子给你,实际上,只有在非用不可的状况下才会使用匿名函数。它们不是你的首选,而且你要知道为何。一旦你这么作了,你的代码会更简洁、容易去阅读,BUG也更容易被捕获,让咱们看看这3个避免使用它们的缘由吧!chrome

堆栈跟踪

你终于写完了代码,不管你有多擅长编码,当你运行代码时,总会有一些报错。有些错误很容易被捕获,但有时并非这样。微信

若是错误很容易被捕获到,好的,那说明你知道他们错在哪!为此,咱们使用所谓的堆栈跟踪,若是你对堆栈跟踪一点都不了解,Google给了咱们很好的介绍ide

假设咱们有一个很简单的项目:chrome-devtools

function start () {
  (function middle () {
    (function end () {
      console.lg('test');
    })()
  })()
}复制代码

但看起来咱们作了一些愚蠢得难以置信的事,就像拼错console.log。在咱们这个小项目中,这没什么大不了的。但也许这是一个巨型项目中的一个片断,有大量的模块与它相互依赖。最重要的是,让咱们伪装你没有烦这种愚蠢的错误。那个初级开发者在他准备离开度假的前一天,把它推到了仓库中!函数

如今,咱们将去跟踪错误。根据咱们精确的命名函数,咱们获得的堆栈跟踪像下面这样:

幸亏你给函数命名了,初级开发者!如今,咱们能轻松的跟踪到这个BUG。

可是...一旦咱们修复了它,又会出现新的BUG。这时,就要请出更高级的开发者了。他们知道如何使用匿名函数,并大量的使用在他们的代码中。结果是,他们发现了一个BUG,咱们去跟踪BUG。

他们的代码:

(function () {
 (function () {
   (function () {
     console.lg('test');
    })();
  })();
})();复制代码

多使人惊讶,这个高级开发者也忘了怎么拼写console.log!这是一个偶然吗?!告诉你一个悲痛的消息,他们没有给函数命名。

控制台会展现什么给咱们?

没事...咱们还有行号提示? 在这个例子中,咱们好像有7行代码。若是咱们在处理一个巨大的代码库?若是每行有10k的代码?若是行号相差很远?若是代码被压缩了、没有map文件、行号提示几乎是没用的?

我认为你能够很是容易的回答这些问题。答案是:你会度过糟糕的一天

可读性

看吧,我知道你不服气。你仍然爱着匿名函数,并且你永远也不会有BUG。抱歉,我忘了告诉你如何写出完美的代码。让咱们来看看这点!

检查下面两个不一样的代码示例:

function initiate (arguments) {
  return new Promise((resolve, reject) => {
    try {
      if (arguments) {
         return resolve(true);
      }
      return resolve(false);
    } catch (e) {
      reject(e);
    }
  });
}

initiate(true)
  .then(res => {
        if (res) {
          doSomethingElse();
        } else {
          doSomething();
        }
  ).catch(e => {
            logError(e.message);
            restartApp();
          }
  );复制代码

这是一我的为的例子,但我认为你能get到那个点。咱们有一个方法,它返回一个Promise对象,咱们用这个对象去管理可能返回的不一样请求。

你或许认为这个代码阅读起来不太难,但我认为它能写的更好。

若是咱们摆脱全部匿名函数,结果会如何?

function initiate (arguments) {
  return new Promise(checkForArguments);
}
function checkForArguments (resolve, reject) {
  try {
    if (arguments) {
     return resolve(true);   
    }
    return resolve(false);
  } catch (e) {
    reject(e);
  }
}
function evaluateRes (res) {
  if (res) {
    doSomethingElse();
  } else {
    doSomething();
  }
}
function handleError (e) {
  logError(e.message);
  restartApp();
}
initiate(true)
  .then(evaluateRes)
  .catch(handleError);复制代码

好了,让咱们来屡清一下思路:这段代码比以前的要长,但我认为它比以前的可读性高得多!咱们使用了很是棒的命名函数而不是匿名函数。只要咱们看到命名函数,它的名字就会暗示咱们接下来会发生什么。它消除了咱们在阅读代码时的心理障碍。

这也有利于独立问题。不只仅是建立方法,传递参数,运行逻辑,在第二个例子中,传递参数给thencatch,咱们能够很清楚的知道函数中的每一处都发生了什么。

时间很少了,不然我要让你信服这些代码能够更加易读。也许你任然不相信,那尝试看看第三个论据...

可重用性

你有注意到最后一个例子吗?全部函数都是能够互相调用的!

当你使用匿名函数时,它们很难遍及你的程序。重用代码能够下降能耗,你也不用一遍遍写重复的代码了。还有你们都知道的一点,代码越少,引入BUG的概率越小,并且用户能够加载更少的资源。双赢的局面!

相反的,命名函数能够在它的整个做用域中使用,而不须要像变量同样四处传递。你写的代码会很天然的更具重用性,由于,你能够重用他们!

匿名函数好吗?

是的。我必须认可,有时它们也是最好的选择!

const stuff = [
  { hide: true, name: 'justin' },
  { hide: false, name: 'lauren' },
  { hide: false, name: 'max' },
];
const filteredStuff = stuff.filter(s => !s.hide);复制代码

这个匿名函数s => !s.hide小而简洁,它不会污染其它地方,也不会用在其它地方。它会在stuff.filter的堆栈跟踪中显示。若是你须要重用它,最好重用整个语句:

function filterByHide (array) {
  return array.filter(item => !item.hide);
}复制代码

有时你须要包裹你全部的代码在一个匿名函数中,以保证全局做用域不被污染。

(() => {
 ... your code here ...
})();复制代码

顶级匿名函数不会影响到堆栈跟踪。代码重用是不会形成伤害的,由于代码重用的所有目的就是保持方法被包含。

我相信还有其余地方适合使用匿名函数,在评论中分享一下吧!

感谢阅读,离开这里后,中止写匿名函数吧!

喜欢本文的朋友能够关注个人微信公众号,不按期推送一些好文。

本文由Rockjins Blog翻译,转载请与译者联系。不然将追究法律责任。

相关文章
相关标签/搜索