看看这些被同事喷的JS代码风格你写过多少

殷荣桧 JavaScript 今天

现在写代码比以前好多了,代码的格式都有eslint,prettier,babel(写新版语法)这些来保证,然而,技术手段再高端都不能解决代码可读性(代码能否被未来的自己和同事看懂)的问题,因为这个问题只有人自己才能解决。我们写代码要写到下图中左边这样基本上就功德圆满了。

注:由于个人水平与眼界的原因,这篇文章中并没有完全覆盖到常见的写代码的不好的习惯,所以你如果觉的有需要补充的,都可以在文章下方评论,或者直接到我的Github的这篇文章中评论。对于有用的,都将补充到我的掘金和Github中去。同时,你如果觉的文章写得还可以,Please在我的Github中送上你宝贵的Star,你的Star是我继续写文章最大的动力。

一、变量相关

(1)变量数量的定义

NO:滥用变量:


 
  1. let kpi = 4;  // 定义好了之后再也没用过

  2. function example() {

  3.    var a = 1;

  4.    var b = 2;

  5.    var c = a+b;

  6.    var d = c+1;

  7.    var e = d+a;

  8.    return e;

  9. }

YES: 数据只使用一次或不使用就无需装到变量中


 
  1. let kpi = 4;  // 没用的就删除掉,不然过三个月自己都不敢删,怕是不是那用到了

  2. function example() {

  3.    var a = 1;

  4.    var b = 2;

  5.    return 2a+b+1;

  6. }

(2)变量的命名

NO:自我感觉良好的缩写


 
  1. let fName = 'jackie'; // 看起来命名挺规范,缩写,驼峰法都用上,ESlint各种检测规范的工具都通过,But,fName是啥?这时候,你是不是想说What are you 弄啥呢?

  2. let lName = 'willen'; // 这个问题和上面的一样

YES:无需对每个变量都写注释,从名字上就看懂


 
  1.  let firstName = 'jackie'; // 怎么样,是不是一目了然。少被喷了一次

  2.  let lastName = 'willen';

(3)特定的变量

NO:无说明的参数


 
  1. if (value.length < 8) { // 为什么要小于8,8表示啥?长度,还是位移,还是高度?Oh,my God!!

  2.    ....

  3. }

YES:添加变量


 
  1. const MAX_INPUT_LENGTH = 8;

  2. if (value.length < MAX_INPUT_LENGTH) { // 一目了然,不能超过最大输入长度

  3.    ....

  4. }

(4)变量的命名

NO:命名过于啰嗦


 
  1. let nameString;

  2. let theUsers;

YES: 做到简洁明了


 
  1. let name;

  2. let users;

(5)使用说明性的变量(即有意义的变量名)

NO:长代码不知道啥意思


 
  1. const address = 'One Infinite Loop, Cupertino 95014';

  2. const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;

  3. saveCityZipCode(

  4.  address.match(cityZipCodeRegex)[1], // 这个公式到底要干嘛,对不起,原作者已经离职了。自己看代码

  5.  address.match(cityZipCodeRegex)[2], // 这个公式到底要干嘛,对不起,原作者已经离职了。自己看代码

  6. );

YES:用变量名来解释长代码的含义


 
  1. const address = 'One Infinite Loop, Cupertino 95014';

  2. const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;

  3. const [, city, zipCode] = address.match(cityZipCodeRegex) || [];

  4. saveCityZipCode(city, zipCode);

(6)避免使用太多的全局变量

NO:在不同的文件不停的定义全局变量


 
  1. name.js

  2. window.name = 'a';

  3. hello.js

  4. window.name = 'b';

  5. time.js

  6. window.name = 'c';  //三个文件的先后加载顺序不同,都会使得window.name的值不同,同时,你对window.name的修改了都有可能不生效,因为你不知道你修改过之后别人是不是又在别的说明文件中对其的值重置了。所以随着文件的增多,会导致一团乱麻。

YES:少用或使用替代方案 你可以选择只用局部变量。通过(){}的方法。


 
  1. 如果你确实用很多的全局变量需要共享,你可以使用vuex,redux或者你自己参考flux模式写一个也行。

(7) 变量的赋值。

NO:对于求值获取的变量,没有兜底。


 
  1. const MIN_NAME_LENGTH = 8;

  2. let lastName = fullName[1];

  3. if(lastName.length > MIN_NAME_LENGTH) { // 这样你就给你的代码成功的埋了一个坑,你有考虑过如果fullName = ['jackie']这样的情况吗?这样程序一跑起来就爆炸。要不你试试。

  4.    ....

  5. }

YES:对于求值变量,做好兜底。


 
  1. const MIN_NAME_LENGTH = 8;

  2. let lastName = fullName[1] || ''; // 做好兜底,fullName[1]中取不到的时候,不至于赋值个undefined,至少还有个空字符,从根本上讲,lastName的变量类型还是String,String原型链上的特性都能使用,不会报错。不会变成undefined。

  3. if(lastName.length > MIN_NAME_LENGTH) {

  4.    ....

  5. }

  6. 其实在项目中有很多求值变量,对于每个求值变量都需要做好兜底。

  7. let propertyValue = Object.attr || 0; // 因为Object.attr有可能为空,所以需要兜底。

  8. 但是,赋值变量就不需要兜底了。

  9. let a = 2; // 因为有底了,所以不要兜着。

  10. let myName = 'Tiny'; // 因为有底了,所以不要兜着。

二、函数相关

(1)函数命名

NO:从命名无法知道返回值类型


 
  1. function showFriendsList() {....} // 现在问,你知道这个返回的是一个数组,还是一个对象,还是true or false。你能答的上来否?你能答得上来我请你吃松鹤楼的满汉全席还请你不要当真。

Yes: 对于返回true or false的函数,最好以should/is/can/has开头


 
  1. function shouldShowFriendsList() {...}

  2. function isEmpty() {...}

  3. function canCreateDocuments() {...}

  4. function hasLicense() {...}

(2) 功能函数最好为纯函数

NO: 不要让功能函数的输出变化无常。


 
  1. function plusAbc(a, b, c) {  // 这个函数的输出将变化无常,因为api返回的值一旦改变,同样输入函数的a,b,c的值,但函数返回的结果却不一定相同。

  2.        var c = fetch('../api');

  3.        return a+b+c;

  4. }

YES:功能函数使用纯函数,输入一致,输出结果永远唯一


 
  1. function plusAbc(a, b, c) {  // 同样输入函数的a,b,c的值,但函数返回的结果永远相同。

  2.        return a+b+c;

  3. }

(3)函数传参

NO:传参无说明


 
  1. page.getSVG(api, true, false); // true和false啥意思,一目不了然

YES: 传参有说明


 
  1. page.getSVG({

  2.    imageApi: api,

  3.    includePageBackground: true, // 一目了然,知道这些true和false是啥意思

  4.    compress: false,

  5. })

(4)动作函数要以动词开头

NO: 无法辨别函数意图


 
  1. function emlU(user) {

  2.    ....

  3. }

YES:动词开头,函数意图就很明显


 
  1. function sendEmailToUser(user) {

  2.    ....

  3. }

(5)一个函数完成一个独立的功能,不要一个函数混杂多个功能

这是软件工程中最重要的一条规则,当函数需要做更多的事情时,它们将会更难进行编写、测试、理解和组合。当你能将一个函数抽离出只完成一个动作,他们将能够很容易的进行重构并且你的代码将会更容易阅读。如果你严格遵守本条规则,你将会领先于许多开发者。

NO:函数功能混乱,一个函数包含多个功能。最后就像能以一当百的老师傅一样,被乱拳打死(乱拳(功能复杂函数)打死老师傅(老程序员))


 
  1. function sendEmailToClients(clients) {

  2.  clients.forEach(client => {

  3.    const clientRecord = database.lookup(client)

  4.    if (clientRecord.isActive()) {

  5.      email(client)

  6.    }

  7.  })

  8. }

YES: 功能拆解,


 
  1. function sendEmailToActiveClients(clients) {  //各个击破,易于维护和复用

  2.  clients.filter(isActiveClient).forEach(email)

  3. }

  4. function isActiveClient(client) {

  5.  const clientRecord = database.lookup(client)

  6.  return clientRecord.isActive()

  7. }

(6)优先使用函数式编程

NO: 使用for循环编程


 
  1. for(i = 1; i <= 10; i++) { // 一看到for循环让人顿生不想看的情愫

  2.   a[i] = a[i] +1;

  3. }

YES:使用函数式编程


 
  1. let b = a.map(item => ++item) // 怎么样,是不是很好理解,就是把a的值每项加一赋值给b就可以了。现在在javascript中几乎所有的for循环都可以被map,filter,find,some,any,forEach等函数式编程取代。

(7) 函数中过多的采用if else ..

No: if else过多


 
  1. if (a === 1) {

  2.    ...

  3. } else if (a ===2) {

  4.    ...

  5. } else if (a === 3) {

  6.    ...

  7. } else {

  8.   ...

  9. }

YES: 可以使用switch替代或用数组替代


 
  1. switch(a) {

  2.   case 1:

  3.           ....

  4.   case 2:

  5.           ....

  6.   case 3:

  7.           ....

  8.  default:

  9.       ....

  10. }

  11. Or

  12. let handler = {

  13.    1: () => {....},

  14.    2: () => {....}.

  15.    3: () => {....},

  16.    default: () => {....}

  17. }

  18. handler[a]() || handler['default']()

三、尽量使用ES6,有可以能的话ES7中新语法(只罗列最常用的新语法,说实话,有些新语法不怎么常用)

(1)尽量使用箭头函数

NO:采用传统函数


 
  1. function foo() {

  2.  // code

  3. }

YES:使用箭头函数


 
  1. let foo = () => {

  2.  // code

  3. }

(2)连接字符串

NO:采用传统+号


 
  1. var message = 'Hello ' + name + ', it\'s ' + time + ' now'

YES:采用模板字符


 
  1. var message = `Hello ${name}, it's ${time} now`

(3) 使用解构赋值

NO:使用传统赋值:


 
  1. var data = { name: 'dys', age: 1 };

  2. var name = data.name;

  3. var age = data.age;

  4. var fullName = ['jackie', 'willen'];

  5. var firstName = fullName[0];

  6. var lastName = fullName[1];

YES:使用结构赋值:


 
  1. const data = {name:'dys', age:1};

  2. const {name, age} = data;   // 怎么样,是不是简单明了

  3. var fullName = ['jackie', 'willen'];

  4. const [firstName, lastName] = fullName;

(4) 尽量使用类class

NO: 采用传统的函数原型链实现继承


 
  1. 典型的 ES5 的类(function)在继承、构造和方法定义方面可读性较差,当需要继承时,优先选用 class。代码太多,就省略了。

YES:采用ES6类实现继承


 
  1. class Animal {

  2.  constructor(age) {

  3.    this.age = age

  4.  }

  5.  move() {

  6.    /* ... */

  7.  }

  8. }

  9. class Mammal extends Animal {

  10.  constructor(age, furColor) {

  11.    super(age)

  12.    this.furColor = furColor

  13.  }

  14.  liveBirth() {

  15.    /* ... */

  16.  }

  17. }

  18. class Human extends Mammal {

  19.  constructor(age, furColor, languageSpoken) {

  20.    super(age, furColor)

  21.    this.languageSpoken = languageSpoken

  22.  }

  23.  speak() {

  24.    /* ... */

  25.  }

  26. }

先写到这了,这是目前为止发现的问题,这篇文章中并没有完全覆盖到常见的写代码的不好的习惯,所以你如果觉的有需要补充的,都可以在文章下方评论,或者直接到我的Github的这篇文章中评论。对于有用的,都将补充到我的掘金和Github中去。同时,你如果觉的文章写得还可以,Please在我的Github中送上你宝贵的Star,你的Star是我继续写文章最大的动力。


 
  1. 注:除了上述这些人为习惯之外,就像前面提到的,对于机械性的,你可以使用Babel、Eslint、Prettier这些工具来保证代码的格式一致。

参考资料

https://blog.risingstack.com/javascript-clean-coding-best-practices-node-js-at-scale/(JavaScript Clean Coding Best Practices)

https://www.zhihu.com/question/20635785 (如何写出优美的 JavaScript 代码?)

END

作者:殷荣桧

https://juejin.im/post/5becf928f265da61380ec986

教你如何做一个优雅的Ecmascripter /转的更多相关文章

  1. 教你动手做一个 iOS 越狱 app

    前言 俗话说得好, 万事开头难. 仅仅是上图一个如此简单地不能再简单的小app, 其实都不算是app, 只是注入了一段代码进系统中, 等到特定的函数方法调用的时候就会被我们hook掉, 执行我们写的代 ...

  2. 论好的代码习惯的养成/做一个优雅的coder

    1.先说一下以前被滴滴大佬教育的事情: 以前写代码的时候,因为只需要取特定的几个字段,所以经常这么写 //Request $request for example $parameters = $req ...

  3. 3分钟教你做一个iphone手机浏览器

    3分钟教你做一个iphone手机浏览器 第一步:新建一个Single View工程: 第二步:新建好工程,关闭arc. 第三步:拖放一个Text Field 一个UIButton 和一个 UIWebV ...

  4. R数据分析:跟随top期刊手把手教你做一个临床预测模型

    临床预测模型也是大家比较感兴趣的,今天就带着大家看一篇临床预测模型的文章,并且用一个例子给大家过一遍做法. 这篇文章来自护理领域顶级期刊的文章,文章名在下面 Ballesta-Castillejos ...

  5. 【酷Q插件制作】教大家做一个简单的签到插件

    酷Q插件已经有很多了,社区分享一大堆,不过还是自己写才有乐趣,哈哈.不得不吐槽一下,酷Q竟然不更新了,出了个酷Q pro,还收费!!诶.不过这也影响不了咱写插件的心情,今天教大家写一个酷Q签到插件,虽 ...

  6. TTS-零基础入门-10分钟教你做一个语音功能

    在本片博客正式開始之前,大家先跟我做一个简单的好玩的 小语音. 新建一个文本文档,然后再文档里输入这样 一句话  CreateObject("SAPI.SpVoice").Spea ...

  7. Vue+ElementUI: 手把手教你做一个audio组件

    目的 本项目的目的是教你如何实现一个简单的音乐播放器(这并不难) 本项目并不是一个可以用于生产环境的element播放器,所以并没有考虑太多的兼容性问题 本项目不是ElementUI的一个音频插件,只 ...

  8. 用RecyclerView做一个小清新的Gallery效果 - Ryan Lee的博客

    一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...

  9. fir.im Weekly - 如何做一个出色的程序员

    做一个出色的程序员,困难而高尚.本期 fir.im Weekly 精选了一些实用的 iOS,Android 开发工具和源码分享,还有一些关于程序员的成长 Tips 和有意思有质量的线下活动~ How ...

随机推荐

  1. 【C++】const成员函数

    形式: 在成员函数后面加上const限定词,表示不会修改对象内容. 例如Circle类: class Circle { double r; public: Circle(double newr) { ...

  2. 10个你必须知道的jQueryMobile代码片段(转)

    1.在列表项和按钮上禁用文本截断      如果你的列表项或者按钮上是一个很长的文本,它将会被jQuery Mobile自动截断,要禁用这个截断设置,需要在CSS选择器上添加属性"white ...

  3. JSP开发中对jstl的引用方式(标签库引用)

    创建标签库引用文件taglibs.inc 一 采用本地标签库的taglibs.inc文件 <%--struts库标签 --%> <%@ taglib uri="/WEB-I ...

  4. C# 编码命名规则

    C# 编码命名规则 各种类型命名规范总结 类型 命名规则 注意事项 实例 类或结构 Pascal 首字符大写 HttpContext 接口 Pascal 加前缀I IDataAdaper 枚举名 Pa ...

  5. Linux时间子系统(十六) clockevent

    一.clock event控制的通用逻辑 1.产生clock event的设备 各种系统的timer硬件形形色色,不过在general clock event device layer,struct ...

  6. Accelerated C++学习笔记7—&lt;使用库算法&gt;

    第6章  使用库算法 本章中主要教我们怎样使用几个库算法来解决与处理字符串和学生成绩相关的问题. 1.分析字符串 使用一个循环来连接两幅字符图案 <span style="font-f ...

  7. js 重写 bootstrap 样式 alert/confirm 消息窗口

    相信很多人都受够了 alert.confirm 的样子,最近正在用 bootstrap 做项目,顺便封装了一个 bootstrap 样式的消息框. 实现起来很简单,bootstrap 本身就自带了 m ...

  8. bs-web项目时会经常打断点跟踪信息,可是循环时总是F10、F10的按,那么把所数据打印出来查看会更方便

    bs-web项目时会经常打断点跟踪信息,可是循环时总是F10.F10的按,那么把所数据打印出来查看会更方便 一.打断点的方式适合在有错误产生的时候用很好用. 二.可是在分析数据时不直观,得一个一个循环 ...

  9. PHP位操作符

    二进制怎么算 http://www.doc88.com/p-474114598610.html 这个涉及到系统底层,WEB开发中几乎没用到,知道下有这个东西就好了.底层的东西解释总是简单不了的. 变量 ...

  10. nginx学习之epoll

    https://blog.csdn.net/mmshixing/article/details/51848673 首先说一下传统的I/O多路复用select和poll,对比一下和epoll之间的区别: ...