大家好,我是 漫步,日常写代码中难免需要给别人看,如何写出不被人喷的代码,一起看看这篇文章,喜欢记得关注我并设为星标及时收到。

作者:殷荣桧@腾讯

目录:

一、变量相关

二、函数相关

三、尽量使用ES6,有可以能的话ES7中新语法

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

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

一、变量相关

(1)变量数量的定义NO:滥用变量:

let kpi = 4;  // 定义好了之后再也没用过
function example() {var a = 1;var b = 2;var c = a+b;var d = c+1;var e = d+a;return e;
}

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

let kpi = 4;  // 没用的就删除掉,不然过三个月自己都不敢删,怕是不是那用到了
function example() {var a = 1;var b = 2;return 2*a+b+1;
}

(2)变量的命名NO:自我感觉良好的缩写

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

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

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

(3)特定的变量NO:无说明的参数

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

YES:添加变量

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

(4)变量的命名NO:命名过于啰嗦

let nameString;
let theUsers;

YES:做到简洁明了

let name;
let users;

(5)使用说明性的变量(即有意义的变量名)NO:长代码不知道啥意思

const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1], // 这个公式到底要干嘛,对不起,原作者已经离职了。自己看代码address.match(cityZipCodeRegex)[2], // 这个公式到底要干嘛,对不起,原作者已经离职了。自己看代码
);

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

const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

(6)避免使用太多的全局变量NO:在不同的文件不停的定义全局变量

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

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

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

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

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

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

const MIN_NAME_LENGTH = 8;
let lastName = fullName[1] || ''; // 做好兜底,fullName[1]中取不到的时候,不至于赋值个undefined,至少还有个空字符,从根本上讲,lastName的变量类型还是String,String原型链上的特性都能使用,不会报错。不会变成undefined。
if(lastName.length > MIN_NAME_LENGTH) {....
}
其实在项目中有很多求值变量,对于每个求值变量都需要做好兜底。
let propertyValue = Object.attr || 0; // 因为Object.attr有可能为空,所以需要兜底。
但是,赋值变量就不需要兜底了。
let a = 2; // 因为有底了,所以不要兜着。
let myName = 'Tiny'; // 因为有底了,所以不要兜着。

二、函数相关

(1)函数命名NO:从命名无法知道返回值类型

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

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

function shouldShowFriendsList() {...}
function isEmpty() {...}
function canCreateDocuments() {...}
function hasLicense() {...}

(2) 功能函数最好为纯函数NO: 不要让功能函数的输出变化无常。

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

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

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

(3)函数传参NO:传参无说明

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

YES: 传参有说明

page.getSVG({imageApi: api,includePageBackground: true, // 一目了然,知道这些true和false是啥意思compress: false,
})

(4)动作函数要以动词开头NO: 无法辨别函数意图

function emlU(user) {....
}

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

function sendEmailToUser(user) {....
}

(5)一个函数完成一个独立的功能,不要一个函数混杂多个功能这是软件工程中最重要的一条规则,当函数需要做更多的事情时,它们将会更难进行编写、测试、理解和组合。当你能将一个函数抽离出只完成一个动作,他们将能够很容易的进行重构并且你的代码将会更容易阅读。如果你严格遵守本条规则,你将会领先于许多开发者。NO:函数功能混乱,一个函数包含多个功能。最后就像能以一当百的老师傅一样,被乱拳打死(乱拳(功能复杂函数)打死老师傅(老程序员))

function sendEmailToClients(clients) {clients.forEach(client => {const clientRecord = database.lookup(client)if (clientRecord.isActive()) {email(client)}})
}

YES:功能拆解,

function sendEmailToActiveClients(clients) {  //各个击破,易于维护和复用clients.filter(isActiveClient).forEach(email)
}function isActiveClient(client) {const clientRecord = database.lookup(client)return clientRecord.isActive()
}

(6)优先使用函数式编程NO: 使用for循环编程

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

YES:使用函数式编程

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

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

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

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

switch(a) {case 1:....case 2:....case 3:....default:....
}
Or
let handler = {1: () => {....},2: () => {....}.3: () => {....},default: () => {....}
}handler[a]() || handler['default']()

三、尽量使用ES6,有可以能的话ES7中新语法(只罗列最常用的新语法,说实话,有些新语法不怎么常用)(1)尽量使用箭头函数NO:采用传统函数

function foo() {// code
}

YES:使用箭头函数

let foo = () => {// code
}

(2)连接字符串NO:采用传统+号

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

YES:采用模板字符

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

(3) 使用解构赋值NO:使用传统赋值:

var data = { name: 'dys', age: 1 };
var name = data.name;
var age = data.age;var fullName = ['jackie', 'willen'];
var firstName = fullName[0];
var lastName = fullName[1];

YES:使用结构赋值:

const data = {name:'dys', age:1};
const {name, age} = data;   // 怎么样,是不是简单明了var fullName = ['jackie', 'willen'];
const [firstName, lastName] = fullName;

(4) 尽量使用类classNO: 采用传统的函数原型链实现继承

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

YES:采用ES6类实现继承

class Animal {constructor(age) {this.age = age}move() {/* ... */}
}class Mammal extends Animal {constructor(age, furColor) {super(age)this.furColor = furColor}liveBirth() {/* ... */}
}class Human extends Mammal {constructor(age, furColor, languageSpoken) {super(age, furColor)this.languageSpoken = languageSpoken}speak() {/* ... */}
}

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

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

参考资料blog.risingstack.com/javascript-…[7] (JavaScript Clean Coding Best Practices)www.zhihu.com/question/20…[8] (如何写出优美的 JavaScript 代码?)

关于本文

作者:殷荣桧
https://juejin.cn/post/6844903714164047879

参考资料

[1]

https://github.com/jackiewillen/blog/issues/14

[7]

https://blog.risingstack.com/javascript-clean-coding-best-practices-node-js-at-scale/

[8]

https://www.zhihu.com/question/20635785

- EOF -

推荐阅读  点击标题可跳转

15个常用的JavaScript简写技巧

如何写出让同事无法维护的代码?

20个简洁的 JS 代码片段

觉得本文对你有帮助?请分享给更多人

推荐关注「前端开发博客」,提升前端技能

我是漫步,分享技术,不止前端,下期见~

最后,欢迎加我的微信,拉你进上百人的前端交流群

创作不易,加个点赞、在看 支持一下哦!

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

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

      现在写代码比以前好多了,代码的格式都有eslint,prettier,babel(写新版语法)这些来保证,然而,技术手段再高端都不能解决代码可读性(代码能否被未来的自己和同事看懂)的问题,因为这个 ...

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

    作者:殷荣桧@腾讯 来自:https://github.com/jackiewillen/blog/issues/14 现在写代码比以前好多了,代码的格式都有 eslint.prettier.babe ...

  3. 关于JS代码风格(整理+自己的意见)

    导读:代码风格,不仅仅是个性的体现,更有利于你的成果的传播.是的,如果你甘愿做一个劳动者,而非共享多赢,那么不用管. 可以先看看这2篇文章,阮一峰的日志,Crockford's coding styl ...

  4. 如何在浏览器上跑深度学习模型?并且一行JS代码都不用写

    翻译 | 林椿眄 编辑 | 周翔 2017 年 8 月,华盛顿大学的陈天奇团队发布了 TVM,和 NNVM 一起组成深度学习到各种硬件的完整优化工具链,支持手机.CUDA.OpenCL.Metal.J ...

  5. 网站真分页js代码该怎么写?

    真分页这个词对程序猿们来说,并不是一个陌生的词汇,但是如果你是初次学习真分页,或许还是得花点时间小小研究下,下面是之前去转盘网(喜欢的可以看看,也可以进入引擎模式)的真分页js部分代码,html部分的 ...

  6. 网站真分页js代码该怎么写? 1

    真分页这个词对程序猿们来说,并不是一个陌生的词汇,但是如果你是初次学习真分页,或许还是得花点时间小小研究下,下面是之前去转盘网(喜欢的可以看看,也可以进入引擎模式)的真分页js部分代码,html部分的 ...

  7. [Js代码风格]浅析模块模式

    1.实例解释模块模式 简明扼要的说,经典的模块模式指的定义一个立即执行的匿名函数.在函数中定义私有函数和私有变量并且返回一个包含公共变量和公共函数作为属性和方法的匿名对象. var classicMo ...

  8. 编写js代码的注意问题

    编写js代码的注意问题 在一对script的标签中有错误的js代码,那么该错误的代码后面的js代码不会执行 如果第一对的script标签中有错误,不会影响后面的script标签中的js代码执行 scr ...

  9. python代码模板_代码风格与文件模板

    1.文件模板 敢问童鞋们,是否有见过其他人的pycharm代码,上方总有一行"注释"一样的代码? 既能保留当时写代码的时间,也能指定文件字符编码,竟然还可以有一个署名!作者权呀! ...

最新文章

  1. 又一次 Java 内存泄漏排查,新技能+1
  2. 用CSS写出一个下拉菜单小箭头
  3. 华为鸿蒙系统内部消息,华为鸿蒙系统内部曝光,并且将于年底发布?网友:还能再假点?...
  4. 循环神经网络:RNN、LSTM、GRU、BPTT
  5. Leet Code OJ 223. Rectangle Area [Difficulty: Easy]
  6. canvas实现的喜羊羊图像效果
  7. 为未来元素添加点击事件的两种写法
  8. MyBatis获取参数值的两种方式以及传参情况
  9. Postman下一个接口要用到上一个接口的数据
  10. 使用Xcode打包上传APP
  11. 外挂技术之-检测和反检测
  12. win10 系统重装后,如何恢复mysql 数据库(mysql-8.0.26-winx64.zip)
  13. java泛型中T和?和有什么区别
  14. 《自控力》 第一章读书笔记
  15. arcgis新建图层信息复制_ArcGIS中的数据库之间复制和粘贴数据
  16. 【SVAC】千目聚云:SVAC2.0已来 未来发展道路一片光明
  17. SCSI PRs命令研究总结3 - Linux中的SCSI相关实现
  18. 如何理解BRD、MRD、PRD这些名词
  19. springboot+mybatis-plus在log控制台输出sql语句
  20. HCIE-Cloud云计算认证考试心得

热门文章

  1. PS图层+移动工具(3)对齐方式 对齐参照调整
  2. html表格自动分列,[css]display: table-cell,用div做分列布局
  3. linux安装远程桌面,卸载删除
  4. CListCtrl类不能响应HDN_ITMECLICK消息?
  5. Rviz显示电脑摄像头
  6. C# 通用对话框用法详解
  7. win10刻录光盘失败,一直显示有准备好写入到光盘中的文件
  8. 【车载以太网】【SOME/IP】(九)解读SOME/IP-SD服务发现协议
  9. ipconfig命令详细图解
  10. win7无线网络适配器打不开