JS编程规范指南
- 原文:github.com/ryanmcdermott/clean-code-javascript
- 说明:本文翻译自 github 上的一个项目,只取部分精华。
一、变量
用有意义且常用的单词命名
- //Bad
- const yyyymmdstr=moment().format('YYYY/MM/DD');
- //Good
- const currentDate=moment().format('YYYY/MM/DD');
保持统一
对同一类型的变量使用相同的命名保持统一:
- //Bad:
- getUserInfo();
- getClientData();
- getCustomerRecord();
- //Good:
- getUser();
每个常量(全大写)都该命名
可以用 ESLint
检测代码中未命名的常量。
- //Bad:
- //其他人知道86400000的意思吗?
- setTimeout(blastoff,864000);
- //Good:
- const MILLISECOND_IN_A_DAY=86400000;
- setTimeout(blastoff,MILLISECOND_IN_A_DAY);
避免无意义的命名
既然创建了一个 car 对象,就没有必要把它的颜色命名为 carColor。
- //Bad:
- const car={
- carMake:'Honda',
- carModel:'Accord',
- carColor:'Blue'
- };
- function paintCar(car){
- car.carColor='Red';
- }
- //Good:
- const car={
- make:'Honda',
- model:'Accord',
- color:'Blue'
- };
- function paintCar(car){
- car.color='Red';
- }
传参使用默认值
- //Bad:
- function createMicrobrewery(name){
- const breweryName=name||'Hipster Brew Co.';
- // ...
- }
- //Good:
- function createMicrobrewery(name='Hipster Brew Co.'){
- // ...
- }
二、函数
函数参数( 最好 2 个或更少 )
如果参数超过两个,建议使用 ES6 的解构语法,不用考虑参数的顺序。
- //Bad:
- function createMenu(title,body,buttonText,cancellable){
- // ...
- }
- //Good:
- function createMenu({title,body.buttonText,cancellable}{
- // ...
- }
- createMenu({
- title:'Foo',
- body:'Bar',
- buttonText:'Baz',
- cancellable:true
- });
一个方法只做一件事情
这是一条在软件工程领域流传久远的规则。严格遵守这条规则会让你的代码可读性更好,也更容易重构。如果违反这个规则,那么代码会很难被测试或者重用。
- //Bad:
- function emailClients(clients){
- clients.foreach(client =>{
- const clientRecord = database.lookup(client);
- if(clientRecord.isActive()){
- email(client);
- }
- });
- }
- //Good:
- function emailActiveClients(clients){
- clients
- .filter(isActiveClient)
- .forEach(email);
- }
- function isActiveClient(client){
- const clientRecord = database.lookup(client);
- return clientRecord.isActive();
- }
函数名上体现它的作用
- //Bad:
- function addToDate(date,month){
- // ...
- }
- const date = new Date();
- //很难知道是把什么加到日期中
- addToDate(date,1);
- //Good:
- function addMonthToDate(month,date){
- // ...
- }
- const date = new Date();
- addMonthToDate(1,date);
删除重复代码,合并相似函数
很多时候虽然是同一个功能,但由于一两个不同点,让你不得不写两个几乎相同的函数。
- /Bad:
- function showDeveloperList(developers){
- developers.forEach((developer)=>{
- const expectedSalary = developer.calculateExpectedSalary;
- const experience = developer.getExperience();
- const githubLink = developer.getGithubLink();
- const data={
- expectedSalary,
- experience,
- githubLink
- };
- render(data);
- });
- }
- function showManagerList(managers){
- managers.forEach((manager)=>{
- const expectedSalary = manager.calculateExpectedSalary();
- const experience = manager.getExperience();
- const portfolio = manager.getMBAProjects();
- const data={
- expectedSalary,
- experience,
- portfolio
- };
- render(data);
- });
- }
- //Good:
- function showEmployeeList(employees){
- employees.forEach((employee)=>{
- const expectedSalary = employee.getExpectedSalary();
- const experience = employee.getExperience();
- const data = {
- expectedSalary,
- experience,
- }
- switch(employee.type){
- case 'develop':
- data.githubLink=employee.getGithubLink();
- break;
- case 'manager':
- data.portfolio = employee.getMBAProjects();
- break;
- }
- render(data);
- });
- }
使用 Object.assign 设置默认属性
- //Bad:
- const menuConfig = {
- title: null,
- body: 'bar',
- buttonText: null,
- cancellable: true
- };
- function createMenu(config){
- config.title = config.title || 'Foo';
- config.body = config.body || 'Bar';
- config.buttonText = config.buttonText || 'Baz';
- config.cancellable = config.cancellable !== undefined ? config.cancellable:true;
- }
- createMenu(menuConfig);
- //Good:
- const menuConfig = {
- title: 'Order',
- //不包含body
- buttonText: 'Send',
- cancellable: true
- };
- function createMenu(config){
- config = Object.assign({
- title: 'Foo',
- body: 'Bar',
- buttonText: 'Baz',
- cancellable:true
- },config);
- // config:{title: "order",body:"Bar",buttonText:"Send",cancellable:true}
- // ...
- }
尽量不要写全局方法
在 JavaScript 中,永远不要污染全局,会在生产环境中产生难以预料的 bug。举个例子,比如你在 Array.prototype 上新增一个 diff 方法来判断两个数组的不同。而你同事也打算做类似的事情,不过他的 diff 方法是用来判断两个数组首位元素的不同。很明显你们方法会产生冲突,遇到这类问题我们可以用 ES2015/ES6 的语法来对 Array 进行扩展。
- //Bad:
- Array.prototype.diff = function diff(comparisonArray){
- const hash = new Set(comparisonArray);
- return this.filter(elem => !hash.has(elem));
- };
- //Good:
- class SuperArray extends Array{
- diff(comparisonArray){
- const hash = new Set(comparisonArray);
- return this.filter(elem=> !hash.has(elem));
- }
- }
尽量别用“非”条件句
- //Bad:
- function isDOMNodeNotPresent(node){
- // ...
- }
- if (!isDOMNodePresent(node)){
- // ...
- }
- //Good:
- function isDOMNodePresent(node){
- // ...
- }
- if(isDOMNodePresent(node)){
- // ...
- }
不要过度优化
现代浏览器已经在底层做了很多优化,过去的很多优化方案都是无效的,会浪费你的时间。
- //Bad:
- // 现代浏览已对此(缓存list.length)做了优化。
- for(let i = 0, len = list.length;i < len;i++){
- // ...
- }
- //Good:
- for(let i = 0; i< list.length; i++){
- // ...
- }
删除弃用代码
弃用代码不用注释,直接删除就对了
三、类
使用 ES6 的 class
在 ES6 之前,没有类的语法,只能用构造函数的方式模拟类,可读性非常差。
- //Good:
- // 动物
- 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() {};
- }
使用链式调用
这种模式相当有用,可以在很多库中都有使用。它让你的代码简洁优雅。
- class Car{
- constructor(make,model,color){
- this.make = make;
- this.model = model;
- this.color = color;
- }
- setMake(make){
- this.make = make;
- }
- setModel(model){
- this.model = model;
- }
- setColor(color){
- this.color = color;
- }
- save(){
- console.log(this.make, this.model., this.color);
- }
- }
- // Bad:
- const car = new Car('Ford','F-150','red');
- car.setColor('pink');
- car.save();
- //Good:
- const car = new Car('Ford','F-150','red')
- .setColor('pink')
- .save();
四、异步
使用 promise 或者 Async/Await 代替回调
- //Bad:
- get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin',(requestErr,response) => {
- if(requestErr){
- consoloe.error(requestErr);
- }else{
- writeFile('article.html',response.body,(writeErr) => {
- if(writeErr){
- console.error(writeErr);
- }else {
- console.log('File written');
- }
- })
- }
- });
- //Good:
- get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
- .then((response) => {
- return writeFile('article.html' ,response);
- })
- .then( (response) => {
- console.log('File written');
- })
- .catch( (err) => {
- console.error(err);
- });
- //perfect:
- async function getCleanCodeArticle(){
- try{
- const response = await get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
- await writeFile('artical.html',response);
- console.log('File written');
- }catch (err){
- console.error(err);
- }
- }
JS编程规范指南的更多相关文章
- JS编程规范
在第一家公司用C++时,公司有着严格的代码规范,甚至到了严苛的地步,现在回想起来,对它充满感激.一个好的习惯让你收益终身. 之后使用JS/TS却没有为自己定一套编程规范,所幸为时不晚,在这里参考air ...
- Node.js编程规范
摘自:https://github.com/dead-horse/node-style-guide https://github.com/felixge/node-style-guide 2空格缩进 ...
- tensorflow2.0编程规范
背景 tensorflow2.0 相比于1.0 有很大变化,1.0版本的placeholder,Session都没有了,2.0版本强推使用keras.keras是一个比较高层的api,确实挺好用的,一 ...
- Batsing的网页编程规范(HTML/CSS/JS/PHP)
特别注意!!!我这里的前端编程规范不苟同于Bootstrap的前端规范. 因为我和它的目的不同,Bootstrap规范是极简主义,甚至有些没有考虑到兼容性的问题. 我的规范是自己从编程实践中总结出来的 ...
- Google的Java编程风格指南(Java编码规范)
这份文档是Google Java编程风格规范的完整定义.当且仅当一个Java源文件符合此文档中的规则, 我们才认为它符合Google的Java编程风格. 与其它的编程风格指南一样,这里所讨论的不仅仅是 ...
- .NET编程规范
.NET开发编程规范 第1章 程序的版式 版式虽然不会影响程序的功能,但会影响可读性.程序的版式追求清晰.美观,是程序风格的重要构成因素. 可以把程序的版式比喻为"书法".好的&q ...
- JavaScript编码规范指南
前言 本文摘自Google JavaScript编码规范指南,截取了其中比较容易理解与遵循的点作为团队的JavaScript编码规范. JavaScript 语言规范 变量 声明变量必须加上 var ...
- Google Java编程风格指南
出处:http://hawstein.com/posts/google-java-style.html 声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Comm ...
- 谷歌Java编程规范
Google Java编程风格指南 January 20, 2014 作者:Hawstein 出处:http://hawstein.com/posts/google-java-style.html 声 ...
随机推荐
- 2018年第九届蓝桥杯国赛试题(JavaA组)
1.结果填空 (满分13分)2.结果填空 (满分39分)3.代码填空 (满分27分)4.程序设计(满分45分)5.程序设计(满分71分)6.程序设计(满分105分) 1.标题:三角形面积 已知三角形三 ...
- 洛谷P1349 广义斐波那契数列(矩阵快速幂)
P1349 广义斐波那契数列 https://www.luogu.org/problemnew/show/P1349 题目描述 广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列.今给定 ...
- 解析Xml文件的三种方式
1.Sax解析(simple api for xml) 使用流式处理的方式,它并不记录所读内容的相关信息.它是一种以事件为驱动的XML API,解析速度快,占用内存少.使用回调函数来实现. clas ...
- C++类型起别名的方式
C++给类型起别名的方式: #include <iostream> using namespace std; #define DString std::string //! 不建议使用!t ...
- 使用ffmpeg编码时,如何设置恒定码率,并控制好关键帧I帧间隔
1. 大家在使用ffmpeg进行视频编码时,使用-b命令,想控制比特率,却发现结果并没有如我们设置所愿,通过码流分析器观察视频码流,码率的波动还是很大的,ffmpeg控制的并不好,这时候,我们可以通过 ...
- 2014 Noip提高组 Day1
P1328 生活大爆炸版石头剪刀布 [题目描述] 石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头.如果两个人出拳一样,则不分胜负.在<生活大爆炸>第二季第8 集中出现了一种石头 ...
- 免打包:简单、灵活、便捷的APP渠道统计方法
相信做过APP运营推广的小伙伴们应该对APP渠道统计并不陌生吧.APP推广运营人员需要根据数据来评估渠道推广的效果,找到最适合自家APP的渠道,有针对性的投放,不断完善推广策略,这样才能更加精准.有效 ...
- ReentrantLock锁 源码分析
根据下面代码分析下ReentrantLock 获得锁和释放锁的过程 ReentrantLock lock = new ReentrantLock(); lock.lock();//获得锁 lock.u ...
- 解决phpwind 9 转换到 discuz x 3.1的头像仍然不显示问题
phpwind 9 转换到 discuz x 3.1后,按照discuz转换程序的步骤做,头像仍然不显示,后来登录后重新上传头像发现,是文件名的原因,如下操作改名即可(还好我的论坛会员不多,不然手改累 ...
- vue中声明式导航和编程式导航
官方文档:https://router.vuejs.org/zh-cn/essentials/navigation.html 声明式导航和编程式导航 共同点: 都能进行导航,都可以触发路由,实现组件切 ...