如何写出漂亮的js代码
栏目: JavaScript · 发布时间: 5年前
内容简介:如何提高代码的可读性、复用性、扩展性。我们将从以下四个方面讨论:对同一类型的变量使用相同的命名保持统一:可以用 ESLint 检测代码中未命名的常量。
如何提高代码的可读性、复用性、扩展性。我们将从以下四个方面讨论:
- 变量
- 函数
- 类
- 异步
一、变量
用有意义且常用的单词命名
// 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 ); // config : {title: "Order", body: "Bar", buttonText: "Send", cancellable: true} // ... } createMenu(menuConfig);
尽量不要写全局方法
在 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() {} } // 人类 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: 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"); }) .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); } }
参考链接
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。