「译」这样写的 JS 代码看着就很舒服

news/2024/7/19 15:21:58 标签: js, 办公软件, mozilla, javascript, gwt
js_content">

原文:https://github.com/ryanmcdermott/clean-code-javascript
本文翻译自 github 上的一个项目,非全文搬运,只取部分精华。

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

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

◆ ◆ ◆  ◆ ◆
长按关注小生分享代码规范点赞最多的前三位(48小时),发 18.88 的小红包鼓励一下,欢迎你来分享!

你的在看我当成喜欢


http://www.niftyadmin.cn/n/1252118.html

相关文章

零基础学 AI 难吗?

随着科技的高速发展&#xff0c;人工智能正成为引领科技创新和产业发展的核心力量&#xff0c;人工智能产品与服务正在持续地渗透到人们的日常工作、生活、学习和社交等领域&#xff0c;也推动了各区域、各类型的科技企业和传统产业企业纷纷向人工智能领域开拓。但是&#xff0…

linux编译ice,linux环境下编译安装ICE

前面我们讲过了在linux环境下通过rpm的方式来安装ICE&#xff0c;这种安装方式可以是比较简单的&#xff0c;自己在安装过程中发现后面PHP无法装在IcePHP.sp模块&#xff0c;也有可能自己在安装过程中某个地方出错了。又尝试通过直接编译的方式去安装ICE&#xff0c;PHP也正常装…

linux命令 dev null,shell中 /dev/null 21是什么意思

我们经常能在 shell 脚本中发现 >/dev/null2>&1这样的语句。以前的我并没有去深入地理解这段命令的作用&#xff0c;照搬照用&#xff0c;直到上周我将这段命令不小心写成了 2>&1>/dev/null&#xff0c;出了一点小问题之后&#xff0c;我才开始去了解这段命…

SourceMap知多少:介绍与实践

作者&#xff1a;腾讯IMWeb前端团队01首先说说sourceMap说起sourceMap大家肯定都不陌生&#xff0c;随着前端工程化的演进&#xff0c;我们打包出来的代码都是混淆压缩过的&#xff0c;当源代码经过转换后&#xff0c;调试就成了一个问题。在浏览器中调试时&#xff0c;如何判断…

linux gdb检查函数栈,GDB调试命令

1、查看源码&#xff1a;list [函数名][行数]2、暂停程序(1)设置断点&#xff1a;a、break [源代码行号][源代码函数名][内存地址]b、break ... if condition ...可以是上述任一参数&#xff0c;condition是条件。例如在循环体中可以设置break ... if i 100 来设置循环次数(…

Flutter 在阿里淘系的体系化建设和业务实践

Flutter 这两年的热度不断提升&#xff0c;行业内投入建设 Flutter 的公司也越来越多&#xff0c;有很明显的上升趋势。作为一个技术框架&#xff0c;Flutter 该有的功能都有了&#xff0c;但要把它应用到业务中去&#xff0c;还得解决工程问题、复用已有的技术积累、融入业务的…

一个可能让你的页面渲染速度提升数倍的CSS属性

浏览器在接收到服务端返回的 HTML 之后&#xff0c;需要把这段数据渲染成用户看到的页面&#xff0c;在开始渲染第一个元素之前可能还需要经过很多步骤。这个过程会适用于整个页面&#xff0c;包括当前不可见的内容。所以在首屏渲染时&#xff0c;是有很大一部分时间花费在用户…

「思考」为什么现在面试总是面试造火箭?

很多人总是抱怨面试官问一些平时不常用的知识点&#xff0c;比如算法呀&#xff0c;网络(TCP)等等&#xff0c;也就是大家常说的&#xff1a;面试造火箭&#xff0c;工作拧螺丝。但是有没有想过为什么整个前端圈&#xff0c;或者绝大部分面试&#xff0c;不仅是前端&#xff0c…