JavaScript 代码整洁之道(1)

101 阅读3分钟

再温习一下 Github 上 star 有 90k 的 Javascript 代码风格指南。基本所有内容都来自 仓库,也可以直接查看原文。

变量

  • 使用意义明确的变量名

    Use meaningful and pronounceable variable names

      // Bad
      const yyyymmdstr = moment().format("YYYY/MM/DD");
      // Good
      const currentDate = moment().format("YYYY/MM/DD");
    
  • 对于相同/类似类型的变量应该用一个统一的变量名进行命名

    Use the same vocabulary for the same type of variable

      // Bad
      getUserInfo();
      getClientData();
      getCustomerRecord();
      // Good
      getUser();
    
  • 使用可搜索的变量命名

    Use searchable names

      // Bad
      setTimeout(blastOff, 86400000);
      // Good
      const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; //86400000;
      setTimeout(blastOff, MILLISECONDS_PER_DAY);
    
  • 使用可解释的变量命名,尽量减少匿名函数使用

    Use explanatory variables

      // Bad
      const address = "One Infinite Loop, Cupertino 95014";
      const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
      saveCityZipCode(
        address.match(cityZipCodeRegex)[1],
        address.match(cityZipCodeRegex)[2]
      );
    
      // Good
      const address = "One Infinite Loop, Cupertino 95014";
      const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
      const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
      saveCityZipCode(city, zipCode);
    
  • 减少「个人心智」的映射,(减少意义模糊的变量命名映射)感觉和第一点其实是一致的

    Avoid Mental Mapping

      // Bad
      const locations = ["Austin", "New York", "San Francisco"];
      locations.forEach(l => {
        doStuff();
        doSomeOtherStuff();
        // ...
        // l 代表什么?意义模糊
        dispatch(l);
      });
    
      // Good
      const locations = ["Austin", "New York", "San Francisco"];
      locations.forEach(location => {
        doStuff();
        doSomeOtherStuff();
        // ...
        dispatch(location);
      });
    
  • 减少冗余的命名方式

    Don't add unneeded context

    // Bad
      const Car = {
        carMake: "Honda",
        carModel: "Accord",
        carColor: "Blue"
      };
    
      function paintCar(car, color) {
        car.carColor = color;
      }
    
      // Good
      const Car = {
        make: "Honda",
        model: "Accord",
        color: "Blue"
      };
    
      function paintCar(car, color) {
        car.color = color;
      }
    
  • 使用参数默认值的方式取代「短路方式」的条件判断赋值

    Use default parameters instead of short circuiting or conditionals

      // Bad
      function createMicrobrewery(name) {
        const breweryName = name || "Hipster Brew Co.";
        // ...
      }
    
      // Good
      function createMicrobrewery(name = "Hipster Brew Co.") {
        // ...
      }
    

函数

  • 函数的参数数量尽量在2个或者2个以下,如果必须使用超过3个以上的参数,可以使用对象来代替,对于es6来说,可以使用对象解构的方式声明函数的参数

    Function arguments (2 or fewer ideally)

      // Bad
      function createMenu(title, body, buttonText, cancellable) {
        // ...
      }
      createMenu("Foo", "Bar", "Baz", true);
    
      // Good
      function createMenu({ title, body, buttonText, cancellable }) {
        // ...
      }
    
  • 一个函数应该只做一件事情,保持函数的单一性

    Functions should do one thing

      // 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();
      }
    
  • 函数的名称应该说明了这个函数的作用,即要有明确的变量意义

    Function names should say what they do

      function addToDate(date, month) {
        // ...
      }
      const date = new Date();
      // Bad function name
      addToDate(date, 1);
      // Good function name
      addMonthToDate(1, date);
    
  • 一个函数内应该只有一层抽象,(如何理解「只有一层抽象」?即不应该还有其他逻辑可以被抽取成单独的函数。这一点其实和一个函数只做一件事有点类型。

    Functions should only be one level of abstraction

    // Bad
      function parseBetterJSAlternative(code) {
        const REGEXES = [
          // ...
        ];
    
        const statements = code.split(" ");
        const tokens = [];
        REGEXES.forEach(REGEX => {
          statements.forEach(statement => {
            // ...
          });
        });
    
        const ast = [];
        tokens.forEach(token => {
          // lex...
        });
    
        ast.forEach(node => {
          // parse...
        });
      }
      // Good。可以拆分出不同的函数逻辑
      function parseBetterJSAlternative(code) {
        const tokens = tokenize(code);
        const syntaxTree = parse(tokens);
        syntaxTree.forEach(node => {
          // parse...
        });
      }
    
      function tokenize(code) {
        const REGEXES = [
          // ...
        ];
    
        const statements = code.split(" ");
        const tokens = [];
        REGEXES.forEach(REGEX => {
          statements.forEach(statement => {
            tokens.push(/* ... */);
          });
        });
    
        return tokens;
      }
    
      function parse(tokens) {
        const syntaxTree = [];
        tokens.forEach(token => {
          syntaxTree.push(/* ... */);
        });
    
        return syntaxTree;
      }
    
  • 减少重复代码,尽量减少重复逻辑的代码

    Remove duplicate code

      // 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。利用switch优化代码
      function showEmployeeList(employees) {
        employees.forEach(employee => {
          const expectedSalary = employee.calculateExpectedSalary();
          const experience = employee.getExperience();
    
          const data = {
            expectedSalary,
            experience
          };
    
          switch (employee.type) {
            case "manager":
              data.portfolio = employee.getMBAProjects();
              break;
            case "developer":
              data.githubLink = employee.getGithubLink();
              break;
          }
    
          render(data);
        });
      }
    

    未完待续...