zoukankan      html  css  js  c++  java
  • 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);
       }
    }
  • 相关阅读:
    CPP Info Memo part3
    在Google搜索结果显示原始链接(转自 月光博客)
    libc 之 locales
    Git 分支管理与本地 repository 创建
    py2exe issue: ImportError: No module named _fontdata_enc_winansi (http://stackoverflow.com/)
    CPP Info Memo (Part 1)
    CPP Info Memo part2
    HOWTO: Increase write speed by 'aligning' FAT32(通过对齐 FAT32 提高U盘访问速度, 转载)
    (转载)Gentoo中文man乱码
    如何选择开源许可证?(转载)
  • 原文地址:https://www.cnblogs.com/wiggin-Z/p/11083155.html
Copyright © 2011-2022 走看看