教你四点写出漂亮的JavaScript 代码

数字探星鹤
• 阅读 101

如何提高代码的可读性、复用性、扩展性。我们将从以下四个方面讨论:
变量
函数

异步

一、变量用有意义且常用的单词命名
[JavaScript] 纯文本查看 复制代码
?

// Bad:
const yyyymmdstr = moment().format('YYYY/MM/DD');
// Good:
const currentDate = moment().format('YYYY/MM/DD');
保持统一对同一类型的变量使用相同的命名保持统一:
[JavaScript] 纯文本查看 复制代码
?

// Bad:
getUserInfo();
getClientData();
getCustomerRecord();
// Good:
getUser()
每个常量(全大写)都该命名可以用 ESLint 检测代码中未命名的常量。
[JavaScript] 纯文本查看 复制代码
?

// Bad:
// 其他人知道 86400000 的意思吗?
setTimeout( blastOff, 86400000 );
// Good:
const MILLISECOND_IN_A_DAY = 86400000;
setTimeout( blastOff, MILLISECOND_IN_A_DAY );
避免无意义的命名既然创建了一个 car 对象,就没有必要把它的颜色命名为 carColor。
[JavaScript] 纯文本查看 复制代码
?

// 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';

}
传参使用默认值
[JavaScript] 纯文本查看 复制代码
?

// Bad:
function createMicrobrewery( name ) {

const breweryName = name || 'Hipster Brew Co.';
// ...

}
// Good:
function createMicrobrewery( name = 'Hipster Brew Co.' ) {

// ...

}
二、函数函数参数( 最好 2 个或更少 )如果参数超过两个,建议使用 ES6 的解构语法,不用考虑参数的顺序。
[JavaScript] 纯文本查看 复制代码
?

// Bad:
function createMenu( title, body, buttonText, cancellable ) {

// ...

}
// Good:
function createMenu( { title, body, buttonText, cancellable } ) {

// ...

}
createMenu({

title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true

});
一个方法只做一件事情这是一条在软件工程领域流传久远的规则。严格遵守这条规则会让你的代码可读性更好,也更容易重构。如果违反这个规则,那么代码会很难被测试或者重用。
[JavaScript] 纯文本查看 复制代码
?

// 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();

}
函数名上体现它的作用
[JavaScript] 纯文本查看 复制代码
?

// Bad:
function addToDate( date, month ) {

// ...

}
const date = new Date();
// 很难知道是把什么加到日期中
addToDate( date, 1 );
// Good:
function addMonthToDate( month, date ) {

// ...

}
const date = new Date();
addMonthToDate( 1, date );
删除重复代码,合并相似函数很多时候虽然是同一个功能,但由于一两个不同点,让你不得不写两个几乎相同的函数。
[JavaScript] 纯文本查看 复制代码
?

// 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.calculateExpectedSalary();
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 设置默认属性
[JavaScript] 纯文本查看 复制代码
?

// 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}
// ...
}
createMenu(menuConfig);
尽量不要写全局方法在 JavaScript 中,永远不要污染全局,会在生产环境中产生难以预料的 bug。举个例子,比如你在 Array.prototype 上新增一个 diff 方法来判断两个数组的不同。而你同事也打算做类似的事情,不过他的 diff 方法是用来判断两个数组首位元素的不同。很明显你们方法会产生冲突,遇到这类问题我们可以用 ES2015/ES6 的语法来对 Array 进行扩展。
[JavaScript] 纯文本查看 复制代码
?

// 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));        

}
}
尽量别用“非”条件句
[JavaScript] 纯文本查看 复制代码
?

// Bad:
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}
// Good:
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}
不要过度优化现代浏览器已经在底层做了很多优化,过去的很多优化方案都是无效的,会浪费你的时间。
[JavaScript] 纯文本查看 复制代码
?

// 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 之前,没有类的语法,只能用构造函数的方式模拟类,可读性非常差。
[JavaScript] 纯文本查看 复制代码
?

// 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() {};
}
使用链式调用这种模式相当有用,可以在很多库中都有使用。它让你的代码简洁优雅。
[JavaScript] 纯文本查看 复制代码
?

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:
class Car {
constructor(make, model, color) {

this.make = make;
this.model = model;
this.color = color;

}

setMake(make) {

this.make = make;
// NOTE: Returning this for chaining
return this;

}

setModel(model) {

this.model = model;
// NOTE: Returning this for chaining
return this;

}

setColor(color) {

this.color = color;
// NOTE: Returning this for chaining
return this;

}

save() {

console.log(this.make, this.model, this.color);
// NOTE: Returning this for chaining
return this;

}
}

const car = new Car("Ford", "F-150", "red").setColor("pink").save();
四、异步使用 promise 或者 Async/Await 代替回调
[JavaScript] 纯文本查看 复制代码
?

// Bad:
get('https://en.wikipedia.org/wiki...', (requestErr, response) => {
if (requestErr) {

console.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...')
.then((response) => {

return writeFile('article.html', response);

})
.then(() => {

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('article.html', response);
console.log('File written');

} catch(err) {

console.error(err);

}
}
更多技术资讯可关注:gzitcast

点赞
收藏
评论区
推荐文章
小嫌 小嫌
3年前
Javascript中的变量提升
定义JavaScript中奇怪的一点是你可以在变量和函数声明之前使用它们。就好像是变量声明和函数声明被提升了代码的顶部一样。sayHi()//Hithere!functionsayHi()console.log('Hithere!')name'JohnDoe'console.log(name)//JohnDoevarn
菜园前端 菜园前端
2年前
为你解惑JS作用域和作用域链知识
原文链接:变量作用域一个变量的作用域(scope)是程序源代码中定义这个变量的区域。全局变量拥有全局作用域,在JavaScript代码中的任何地方都是可以访问的。然而在函数内声明的变量只能在函数体内访问,它们是局部变量,作用域是局部性的。函数参数也是局部变
Jacquelyn38 Jacquelyn38
4年前
JavaScript预解析处理过程原来是这回事
讲解一般来说,Javascript代码的执行包括两个过程:预解析处理过程和逐行解读过程。在代码逐行解读前,Javasript引擎需要进行代码的预处理过程。预解析处理的工作主要是变量提升和给变量分配内存,具体过程是在每个作用域中查找var声明的变量、函数定义和命名函数(函数参数),找到它们后,在当前作用域中给他们分配内存,并给他们设置初始值。预解析设置的初
Stella981 Stella981
3年前
SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器!复制代码(https://oscimg.oschina.net/oscnet/675f5689159acfa2c39c91f4df40a00ce0f.gif)/cookie对象;rememberMeCookie()方法是设置Cookie的生成模
Stella981 Stella981
3年前
2018最新Web前端经典面试试题及答案
javascript: JavaScript中如何检测一个变量是一个String类型?请写出函数实现typeof(obj)"string"typeofobj"string"obj.constructorString请用js去除字符串空格?
Stella981 Stella981
3年前
Python 为什么推荐蛇形命名法?
关于变量的命名,这又是一个容易引发程序员论战的话题。如何命名才能更具有可读性、易写性与明义性呢?众说纷纭。本期“Python为什么”栏目,我们将聚焦于变量命名中的连接方式,来切入这块是非之地,想要回答的问题是——Python为什么要推荐蛇形命名法?首先一点,对于单个字符或者单词(例如:a、A、PYTHON、Cat),当它们被用作变
Stella981 Stella981
3年前
JavaScript 代码整洁之道
代码质量与其整洁度成正比。干净的代码,既在质量上较为可靠,也为后期维护、升级奠定了良好基础。本文并不是代码风格指南,而是关于代码的可读性、复用性、扩展性探讨。我们将从几个方面展开讨论:1.变量2.函数3.对象和数据结构4.类5.SOLID
Stella981 Stella981
3年前
Linux应急响应(四):盖茨木马
0x00前言Linux盖茨木马是一类有着丰富历史,隐藏手法巧妙,网络攻击行为显著的DDoS木马,主要恶意特点是具备了后门程序,DDoS攻击的能力,并且会替换常用的系统文件进行伪装。木马得名于其在变量函数的命名中,大量使用Gates这个单词。分析和清除盖茨木马的过程,可以发现有很多值得去学习和借鉴的地方。0x01应急场景
Easter79 Easter79
3年前
SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器!复制代码(https://oscimg.oschina.net/oscnet/675f5689159acfa2c39c91f4df40a00ce0f.gif)/cookie对象;rememberMeCookie()方法是设置Cookie的生成模
可莉 可莉
3年前
2018最新Web前端经典面试试题及答案
javascript: JavaScript中如何检测一个变量是一个String类型?请写出函数实现typeof(obj)"string"typeofobj"string"obj.constructorString请用js去除字符串空格?
Wesley13 Wesley13
3年前
GO 编码规范
编码规范本规范旨在为日常Go项目开发提供一个代码的规范指导,方便团队形成一个统一的代码风格,提高代码的可读性,规范性和统一性。本规范将从命名规范,注释规范,代码风格和Go语言提供的常用的工具这几个方面做一个说明。该规范参考了go语言官方代码的风格制定。一、命名规范命名是代码规范中很重要的一部分,统一的命名规则有