|
前言无论是开源项目的源码还是用各类脚手架创建项目的模版,我们一定会在配置中看到Lint工具,比如ESLint和Prettier。如果没有深入理解Prettier和ESLint的作用和区别,我们很容易陷入Lint工具麻烦且无用的错觉中。因此本篇文章将深入梳理它们的关系并且利用这两个工具作为切入点讲述一下代码规范以及它们对前端实现clean-code的重要性。PrettierandESLintPrettierWhat?一般提起代码规范大家比较容易想到的是代码呈现出的格式(风格),对于前端来说比如:每行代码空2格/4格、要不要写分号、箭头函数单个参数要不要括号和一行最长多少字母等等格式问题,这个可以对应于Prettier-CodeforFormatter。Prettier官网的定义是pinionated和fewoptions就得出Prettier的特点是:用户自定义不多的样式美化工具。Prettier的英文名也是「更漂亮的」。也就是说它只是美化代码样式并不会检查代码质量。这就是它与ESLint最大的区别。Why?目前基本开源的大型前端项目都会用Prettier,比如:AntDesignVue、elementUI、Vue3和React等等。因为他们每天需要处理来自世界各地的pullrequests,如果没有Prettier应该天天都脑充血。。。。Prettier官网给到的WhyPrettier理由:Buildingandenforcingastyleguide:不需要讨论制定规则,不需要学习任何规则,Prettier强制执行一个固定的代码风格(用户可自定义的规则不多),或许没有100%按照我们自己的意愿格式化所有代码,但是这样开箱即用更加提高效率。HelpingNewcomers:对新手友好,好的代码格式可以避免很多低级错误。Writingcode:格式化代码的设置非常友好,option+shift+F一键美化,写代码的时候不需要花费大量的时间和精力来格式化代码。或者和编辑器相结合,设置formateonsave,在保存时自动格式化。Easytoadopt:Prettier团队在2017年的时候就已经不接受增加更多配置项的issue了,具体看issue。这样做就是为了保持它开箱即用的特点,并且保证新格式化的代码风格不会引起重大争议并被大家轻松接受。ESLintWhat?Lint工具是一种软件质量保证工具,早在零几年微软就开始启用Lint来检查程序,而ESLint是属于Lint的一种前端代码质量保证工具。感兴趣的可以看看Linter进化史。现在的ESLint除了对代码质量的控制,比如:不使用var变量、switch必须要设置default等等之外,也有一些代码风格的控制,比如:是否使用分号和使用tab还是空格等等。Why?代码检查是一种静态分析来寻找有问题的代码,不依赖于具体的编码风格。对于大多数强类型语言,在编译时就会通过内置的检查工具对代码进行检查。但是JavaScript是一个动态的弱类型语言,没有编译过程,需要一个检查低质量代码的工具,这就是ESLint出现的初衷。ESLint的所有规则与Prettier相比都是可选择的unopinionated。你可以使用默认规则或者自定义规则,也可以选择将规则开启/关闭。How?1.基本的使用方法,在项目中安装:npm install eslint --save-dev2.然后使用eslint创建一个配置文件./node_modules/.bin/eslint --init3.然后在配置文件.eslintrc.js中extends:"eslint:recommended"就可以使用ESLint官方推荐的规则,也是非常方便的。也可以自定义需要的规则:{ "rules": { "semi": ["error", "always"], "quotes": ["error", "double"] }}最后,就可以使用eslint去校验文件:./node_modules/.bin/eslint 文件路径.js在ESLint没有--fix来自动修复未通过规则问题的功能时,需要和Prettier结合使用才方便修改,现在也可以不需要Prettier。不过--fix只会修复AST语法树层面所感知的问题,比如:将constb=data.a转换为解构形式const{b}=data、修改代码的缩进、增加/减少分号等,其他的动态层面比如:虽然强制使用===但是fix时并不会将==转换为===,因为这两个意图是有可能不一样的。所以在平时项目开发中有两种方式去快速修复ESLint问题:命令行里运行eslint检查代码文件的同时加上--fix在VSCode里安装eslint插件,进入项目vscode会自动检测项目的eslint配置文件.eslintrc,然后点击allow表示同意eslint作为默认的formate代码的配置。最后就可以愉快的使用formateonsave或者option+shift+F自动格式化了。clean-code因为JS语言并没有编译过程,在没有使用ESLint之前并没有发现原来自己的代码有很多隐藏的bug。下面举一个我在校招面试时被问到的一个🌰:forin 和forof的区别是什么?当时的回答:forin遍历键名key;forof遍历键值value。(当时觉得没毛病)后来在项目中碰到了ESLint对forin的报错:Thebodyofafor-inshouldbewrappedinanifstatementtofilterunwantedpropertiesfromtheprototype(forin里应该用if语言过滤掉原型上不需要的属性)。后来好好研究了一番forin和forof:forin更适合遍历对象而不是数组(遍历键名key)遍历的index(键名)是字符串型的索引,不能直接加减会遍历所有的可枚举属性,包括原型上的属性(可以加hasOwnProperty阻止遍历到原型)遍历顺序有可能不是按照实际数组的内部顺序forof更适合数组(遍历键值value)遍历的只是数组内的元素,而不包括原型属性适用遍历数/数组/字符串/Map/Set等拥有迭代器对象的集合,但是不能遍历对象,因为对象没有迭代器对象。不得不说,ESLint让我涨知识了!所以eslint的每一条都是有一定的考量的,有时候我们觉得不解的时候一般是我们欠缺了相关的知识。下面截图是一些eslint对JS的规则:每一句看似简短的规则可能有很多知识,避免了低级错误也将代码向clean-code方向靠拢。这个规则的原理也是值得学习的东西。不过很多时候代码的质量是很主观的,ESLint并不能解决,所以这里推荐一个已经有53Kstar的针对JavaScript整理的clean-code-javascript,可以给我们带来ESLint无法限制的东西。What?Clean-code-javascript是根据RobertC.Martin的《代码整洁之道》总结出适用于JavaScript的软件质量原则。《代码整洁之道》的观念是:代码质量与其整洁度成正比。干净的代码,既在质量上较为可靠,也为后期维护、升级奠定了良好基础。但是书中的规则是作者作为多年编程人员的实践经验,不必严格遵守所有的规则,有时候一些规则太固化反而会不好,衍生出的clean-code-javascript也是一样,反正具体应该根据实际情况决定。clean-code-javascript的规则一共分为九个章节,分别是:变量、函数、对象和数据结构、类、测试、异步、错误处理、格式化和注释。在每一个章节中又分为具体的规则。举个🌰:函数这一章有一条规则是尽量采用函数式编程,因为函数式的编程具有更干净且便于测试的特点。Bad:const programmerOutput = [ { name: 'Uncle Bobby', linesOfCode: 500 }, { name: 'Suzie Q', linesOfCode: 1500 } ......];// 使用for循环计算programmerOutput对象里linesOfCode的总数var totalOutput = 0;for (var i = 0; i programmer.linesOfCode) .reduce((acc, linesOfCode) => acc + linesOfCode, 0);但是很多时候并不是上述这样一定要将循环转变为函数式编程的形式,我们以Vue的源码为例:// pacakages/template-explorermonaco.editor.setModelMarkers( editor.getModel()!, `@vue/compiler-dom`, // 传入的参数使用链式调用直接计算 errors.filter(e => e.loc).map(formatError) )// packages/complier-coreconst flagNames = Object.keys(PatchFlagNames) //使用Object.keys遍历对象 // 高阶函数进行链式调用 .map(Number) .filter(n => n > 0 & patchFlag & n) .map(n => atchFlagNames[n]) .join(`, `)相对于「for循环」,上述的函数式编程方式其实在vue源码的占比很小很小。因为很多时候在循环的逻辑比较复杂的情况下,都会采用for循环的方式去写,而函数式编程就用在可以一条语句完成需要的功能的时候。当然这个是比较主观的,对于newcoder来说还是需要goodcoder在不同场景下的codereview来提高代码质量。这是视情况而定的。但是对于for-in迭代器,ESLint有两条规则no-iterator和no-restricted-syntax用来限制使用for-in迭代器,推荐使用map/reduce/find/some/every/forEach...等高阶函数完成数组操作,Object.keys/Object.values/Object.entries完成遍历对象生成所需数组的操作。Why?鲁道夫·克劳修斯说过:Theentropyoftheuniversetendstoamaximum(宇宙的熵趋向一个最大值)。他提出的熵增定律是:在一个孤立系统里,如果没有外力做功,其总混乱度(熵)会不断增大,最后到达最混乱无序的状态。所以从熵增原则来看代码的话:一个项目的代码(孤立的系统),如果没有保证代码质量的环节(外力做功),随着时间推移代码量越来越大的情况下,代码质量肯定是会变得越来越混乱甚至到最后无法正常去维护。一旦项目代码的熵超过了一定的界限,但是代码本身的产品还需要不停更新迭代时,就需要去重构代码,将其迁移到最开始整洁、简洁的结构中(降低熵值)。为了不花大力气去重构代码,实际当中需要「外力做功」:比如上面提到的静态代码检查工具和个人编码的质量。How?现目前采用比较多的流程举例:第一步:Pre-commit阶段和lint工具结合(对应本文第一部分),例如:husky/pre-commit+lint-staged工具构建本地提交之前的检查。现目前React已经将lint-staged集成到了脚手架create-react-app中。第二步:团队代码codereview(对应本文第二部分)。GitHub上许多流行项目采用「PR(PullRequest)」工作流的方式,一个PR至少经过三人次review通过才能合入。不过这一块就比较主观了,模式不固定需要根据实际情况去制定。总结由于JavaScript语言没有编译的过程和一些历史因素导致在编写的代码不够稳定,所以在团队开发中需要用Prettier来统一多人的编码风格、用ESLint去做前期的静态检查保证代码的可读性和质量(降低熵值!)。如果在解决ESLint问题的时候搞明白规则背后的意义就更好了,这样不仅提高代码的编码质量而且也会使自己不断向前端的clean-code靠拢。最后,如有错误烦请指正。clean-code-javascript:https://github.com/ryanmcdermott/clean-code-javascript《cleancode》:https://book.douban.com/subject/4199741/husky:https://www.npmjs.com/package/huskypre-commit:https://www.npmjs.com/package/pre-commitlint-staged:https://www.npmjs.com/package/lint-staged
|
|