1. 首页

如何写出漂亮的 JavaScript 代码

原文:github.com/ryanmcdermo…
说明:本文翻译自 github 上的一个项目,非全文搬运,只取部分精华。

如何写出漂亮的 JavaScript 代码

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

  1. 变量
  2. 函数
  3. 异步

一、变量

用有意义且常用的单词命名


// 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, 86400000 ); // 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.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 设置默认属性


// 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); Js中文网 - 前端进阶资源分享(https://www.javascriptc.com/) // config : {title: "Order", body: "Bar", buttonText: "Send", cancellable: true} // ... } createMenu(menuConfig);

JS中文网 – 前端进阶资源教程 www.javascriptC.com
一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容

尽量不要写全局方法

在 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 (!isDOMNodeNotPresent(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() {}; } // 人类 Js中文网 - 前端进阶资源分享(https://www.javascriptc.com/) class Human extends Mammal{ constructor(age, furColor, languageSpoken) { super(age, furColor); this.languageSpoken = languageSpoken; }; speak() {}; }

JS中文网 – 前端进阶资源教程 www.javascriptC.com
一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容

使用链式调用

这种模式相当有用,可以在很多库中都有使用。它让你的代码简洁优雅。


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 代替回调


// Bad: get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (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/Robert_Cecil_Martin') .then((response) => { return writeFile('article.html', response); }) .then(() => { console.log('File written'); }) Js中文网 - 前端进阶资源分享(https://www.javascriptc.com/) .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); } }

链接:https://juejin.im/post/5d0e11196fb9a07eee5ed6d2

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:如何写出漂亮的 JavaScript 代码

链接:https://www.javascriptc.com/2793.html

« 如何在 JavaScript 中更好地使用数组
前端同学进阶必备之JavaScript 内存机制»
Flutter 中文教程资源

相关推荐

QR code