vlambda博客
学习文章列表

如何使用函数式编程写更简洁的JavaScript代码

原文 | https://dev.to/r0r71z/javascript-write-cleaner-code-with-functional-programming-279a
翻译 | web前端开发 (ID:web_qdkf)

作为一个Web全栈开发人员,我花了很多时间来学习和写JavaScript代码,但这些代码依然写得很差,所以就需要花更多的时间去理解它。
确实,当我们需要在基于JS的项目中重构一些遗留或者未维护的代码片段时,常会感到沮丧,因为它们缺少 JSDocs ,它具有的混合变量声明模式const, let, var,函数声明从function f() {}到var f = function() {}或const f = () => {},更重要的是,所有代码一个模块中的一个功能包含在单个功能主体中。
让我们看下面的代码:
  
    
    
  
var fetch = require('node-fetch'); // if using NodeJS
function articles () { var arr = []; return fetch('https://dev.to/api/articles').then(function(a) { if (a) { return a.json().then(function(b) { if (b) { b.forEach((c) => { if (c.tag_list.indexOf('javascript') !== -1 && c.tag_list.indexOf('node') !== -1) { arr.push(c); } }); return arr; } }); } }); }
articles().then(function(d) { console.log(d); });
在上面的示例中,我们尝试使用 DEV API 请求带有'javascript'和'node'标签的有用文章。随着“完成”的定义,随着时间的推移而发生巨大变化,如今,我们不仅只是为了完成工作,而使代码具有可读性和可维护性。
尽管我们可以使用代码注释或JSDocs来解释此代码中的每一行在做什么,但是我们应该考虑利用功能性编程语言的功能。由于我们可以抽象出所使用的功能,因此我们也可以使用一些词来命名它们,从而使代码具有自我描述性。这样,我们就可以将文档保存为要导出的功能。
让我们尝试按照以下步骤重构API调用:
  • 优化代码通常涉及使用最新的语言可用功能。虽然我们可能并不全部了解它们,但是到了此时,所有JavaScript开发人员都应该知道ES6中引入的功能。因此,作为第一步,我想我们应该禁用var代码中的所有声明,对于本示例,这些声明可以与互换const

  
    
    
  
const fetch = require('node-fetch'); // <-
function articles () { const arr = []; // <- ... }
articles().then(function(d) { console.log(d); });
  • 你们中的一些人可能会同意,也有一些人可能会不同意这样的做法,但是我认为,最初在编程中导致真正困难的是正确地命名。这是我们工作的重要组成部分。我们的主要功能名为articles,这是什么意思?这没有任何意义,因为此函数名称未表达任何告诉我们它在做什么的动作。我认为我们应该能够为此功能找到一个更好的名称,因为我们已经知道该功能的目的。

  
    
    
  
function fetchDevArticles () { ... }
fetchDevArticles().then(function(d) { console.log(d); });
新名称似乎合适,但不准确。如果我们想为该函数进行准确的功能命名时,它又会变得非常冗长,以至于阅读起来会很烦人。例如,fetchDevArticlesAndFilterThemByJavascriptAndNodejsTags绝对很难阅读。
  • 我们的函数和变量命名成为一个问题,因为主函数负责同步执行多项操作。在函数式编程中,我们可以为函数指定与其确切行为功能相关的名称。因此,我们可以将main函数拆分为多个描述自身的较小函数。

  
    
    
  
const fetch = require('node-fetch'); // if using NodeJS
const arr = [];
function pushFilteredArticlesToAuxArray (c) { if ( c.tag_list.indexOf('javascript') !== -1 && c.tag_list.indexOf('node') !== -1 ) { arr.push(c); } }
function filterAndReturnValues (b) { if (b) { b.forEach(pushFilteredArticlesToAuxArray); return arr; } }
function fetchJSDevArticles () { return fetch('https://dev.to/api/articles').then(function(a) { if (a) { return a.json().then(filterAndReturnValues); } }); }
fetchJSDevArticles().then(function(d) { console.log(d); });
在不添加代码注释或JSDocs的情况下,我们的代码看起来会更好识别。但是,代码仍然存在一些问题。如你所见,我使用模块数组变量只是为了过滤另一个数组并返回输出。
  • 尽管目前可行,但是如果我们能找到更好的数组方法来帮助我们的话,代码可以变得更加简单。

  
    
    
  
const fetch = require('node-fetch');
const tagsToFilter = ['javascript', 'node'];
const isIncludedIn = (arr) => tag => arr.includes(tag); const byTags = (tags) => (article) => tags.every(isIncludedIn(article.tag_list)); const filterAndReturnValues = (articles) => articles.filter(byTags(tagsToFilter));
function fetchJSDevArticles () { return fetch('https://dev.to/api/articles').then(function(a) { if (a) { return a.json().then(filterAndReturnValues); } }); }
fetchJSDevArticles().then(function(d) { console.log(d); });
这就是巨大的差异!我使用了几种简单的数组方法来减少代码中的行数。而且,我使用箭头函数是因为它允许我们编写单行帮助函数。
现在,我们的代码在字面上更具可读性,因为我为每个函数确切地命名了它的功能。但是还有更多工作要做。
  
    
    
  
const fetch = require('node-fetch');
const tagsToFilter = ['javascript', 'node']; const devArticlesApiURL = 'https://dev.to/api/articles';
const isIncludedIn = (arr) => tag => arr.includes(tag); const byTags = (tags) => (article) => tags.every(isIncludedIn(article.tag_list)); const filterAndReturnValues = (articles) => articles.filter(byTags(tagsToFilter));
const fetchJSDevArticles = () => fetch(devArticlesApiURL) .then(response => response.json()) .then(filterAndReturnValues) .catch(console.log);
fetchJSDevArticles().then(console.log);
这次,我通过将所有回调都转换为单行箭头函数来减少代码,避免使用花括号和return语句。对我来说,这看起来已经不错了,但是基于这些技巧,你将有动力尝试进一步减少代码,至少我希望如此。

结论

为了编写简洁的代码,函数式编程是我们作为JavaScript开发人员需要意识到的一个范例。不要想着自己能够编写出完美的代码,尤其是初学者,这样你可以有机会从错误中成长。但是你应该尽力做到最好,要牢记总有一些可以改进的地方。
总结说明:
  • ES6很重要。

  • 你尝试执行的操作可能有一个数组方法。

  • 如果没有,请尝试lodash :)

  • 代码注释并不总是需要,让代码更具可读性这个比注释更加重要。

  • 力争最好。