js 代码书写规范_函数

  1. ​​​​​​少传参数

    如果参数超过两个,使用 ES2015/ES6 的解构语法,不用考虑参数的顺序。某个参数不写也不会产生参数匹配错误

    Bad:

    searchListTable: function (parameter, type, startTime, endTime, searchInput, pagesize) {
    }

    Good:

    searchListTable: function ({parameter, type, startTime, endTime, searchInput, pagesize}) {
    }

    searchListTable({
           type:‘dataset’,
           startTime:‘2019’,
           endTime:‘2020’,
           searchInput:‘bob’,
           pagesize:‘100’
    });

  2.  只做一件事情

    一个函数只有一个事情比较易读,易测,易懂

    Bad:

    getSchema(res){
        this.getSelvalSchemaFields = res.fields;
        this.encryptColumnsArray = [];
        this.getSelvalSchemaFields.forEach((item, i) => {
            if (item.type.toLowerCase().indexOf('string') > -1) {
                this.encryptColumnsArray.push(item.name);
            }
        })
    }

    Good:

    getSchema(res){
      res.filter(isStringType).forEach(encryptColumns)
    }
    isStringType(re){
      return re.type.indexOf('string')>-1
    }
    bad

    for (var i = 0; i < this.getRuleOutput.length; i++) {
        if (this.getRuleOutput[i].name == 'outputFields') {
            this.outputVal[i] = this.addForm.outputField;
        }
        if (this.getRuleOutput[i].name == 'qualityType') {
            this.outputVal[i] = this.addForm.scoreWay
        }
        if (this.getRuleOutput[i].name == 'outputLimit') {
            this.outputVal[i] = this.addForm.badDataLimit;
        }
        addForm.inputParams.outputGroup[i] = {
            "name": this.getRuleOutput[i].name,
            "value": this.outputVal[i]
        }
    }

    good

    function getOutputVal(name){
        return ({
            'outputFields': this.addForm.outputField,
            'qualityType': this.addForm.scoreWay,
            'outputLimit': this.addForm.badDataLimit,
        })[name]
    }
    for (var i = 0; i < this.getRuleOutput.length; i++) {
        var outputVal = getOutputVal(this.getRuleOutput[i].name)
        addForm.inputParams.outputGroup[i] = {
            "name": this.getRuleOutput[i].name,
            "value": outputVal
        }
    }
  3. 顾名思义

    看函数名就应该知道它是干啥的。

    Bad:

    function addToDate(date, month) {
    }
    const date = new Date();
    // 很难知道是把什么加到日期中
    addToDate(date, 1);

    Good:

    function addMonthToDate(month, date) {
    }
    const date = new Date();
    addMonthToDate(1, date);

  4. 抽象一层
     

    如果函数嵌套过多会导致很难复用以及测试。

    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 ast = lexer(tokens);
      ast.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 lexer(tokens) {
      const ast = [];
      tokens.forEach((token) => {
        ast.push( /* ... */ );
      });

      return ast;
    }

  5. 去重
     

    很多时候虽然是同一个功能,但由于一两个不同点,让你不得不写两个几乎相同的函数。

    要想优化重复代码需要有较强的抽象能力,错误的抽象还不如重复代码。所以在抽象过程中必须要遵循 SOLID 原则(SOLID 是什么?稍后会详细介绍)。

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

  6. 对象设置默认值
     

    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' key 缺失
      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);

     

  7. 不要传 flag 参数

    通过 flag 的 true 或 false,来判断执行逻辑,违反了一个函数干一件事的原则。

    Bad:

    function createFile(name, temp) {
      if (temp) {
        fs.create(`./temp/${name}`);
      } else {
        fs.create(name);
      }
    }

    Good:

    function createFile(name) {
      fs.create(name);
    }
    function createFileTemplate(name) {
      createFile(`./temp/${name}`)
    }

     

  8. 避免副作用(第一部分)

    函数接收一个值返回一个新值,除此之外的行为我们都称之为副作用,比如修改全局变量、对文件进行 IO 操作等。

    当函数确实需要副作用时,比如对文件进行 IO 操作时,请不要用多个函数/类进行文件操作,有且仅用一个函数/类来处理。也就是说副作用需要在唯一的地方处理。

    副作用的三大天坑:随意修改可变数据类型、随意分享没有数据结构的状态、没有在统一地方处理副作用。

    Bad:

    // 全局变量被一个函数引用
    // 现在这个变量从字符串变成了数组,如果有其他的函数引用,会发生无法预见的错误。
    var name = 'Ryan McDermott';

    function splitIntoFirstAndLastName() {
      name = name.split(' ');
    }

    splitIntoFirstAndLastName();

    console.log(name); // ['Ryan', 'McDermott'];

    Good:

    var name = 'Ryan McDermott';
    var newName = splitIntoFirstAndLastName(name)

    function splitIntoFirstAndLastName(name) {
      return name.split(' ');
    }

    console.log(name); // 'Ryan McDermott';
    console.log(newName); // ['Ryan', 'McDermott'];

     

  9. 避免副作用(第二部分)

    在 JavaScript 中,基本类型通过赋值传递,对象和数组通过引用传递。以引用传递为例:

    假如我们写一个购物车,通过 addItemToCart() 方法添加商品到购物车,修改 购物车数组。此时调用 purchase() 方法购买,由于引用传递,获取的 购物车数组 正好是最新的数据。

    看起来没问题对不对?

    如果当用户点击购买时,网络出现故障, purchase() 方法一直在重复调用,与此同时用户又添加了新的商品,这时网络又恢复了。那么purchase() 方法获取到 购物车数组 就是错误的。

    为了避免这种问题,我们需要在每次新增商品时,克隆 购物车数组 并返回新的数组。

    Bad:

    const addItemToCart = (cart, item) => {
      cart.push({ item, date: Date.now() });
    };

    Good:

    const addItemToCart = (cart, item) => {
      return [...cart, {item, date: Date.now()}]
    };

     

  10. 不要写全局方法

    在 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));        
      }
    }

     

  11. 比起命令式我更喜欢函数式编程

    函数式变编程可以让代码的逻辑更清晰更优雅,方便测试。

    Bad:

    const programmerOutput = [
      {
        name: 'Uncle Bobby',
        linesOfCode: 500
      }, {
        name: 'Suzie Q',
        linesOfCode: 1500
      }, {
        name: 'Jimmy Gosling',
        linesOfCode: 150
      }, {
        name: 'Gracie Hopper',
        linesOfCode: 1000
      }
    ];

    let totalOutput = 0;

    for (let i = 0; i < programmerOutput.length; i++) {
      totalOutput += programmerOutput[i].linesOfCode;
    }

    Good:

    const programmerOutput = [
      {
        name: 'Uncle Bobby',
        linesOfCode: 500
      }, {
        name: 'Suzie Q',
        linesOfCode: 1500
      }, {
        name: 'Jimmy Gosling',
        linesOfCode: 150
      }, {
        name: 'Gracie Hopper',
        linesOfCode: 1000
      }
    ];
    let totalOutput = programmerOutput
      .map(output => output.linesOfCode)
      .reduce((totalLines, lines) => totalLines + lines, 0)

     

  12. 封装条件语句

    Bad:

    if (fsm.state === 'fetching' && isEmpty(listNode)) {
      // ...
    }

    Good:

    function shouldShowSpinner(fsm, listNode) {
      return fsm.state === 'fetching' && isEmpty(listNode);
    }

    if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
      // ...
    }

     

  13. 尽量别用条件句

    Bad:

    function isDOMNodeNotPresent(node) {
      // ...
    }

    if (!isDOMNodeNotPresent(node)) {
      // ...
    }

    Good:

    function isDOMNodePresent(node) {
      // ...
    }

    if (isDOMNodePresent(node)) {
      // ...
    }

     

  14. 避免使用条件语句

    Q:不用条件语句写代码是不可能的。

    A:绝大多数场景可以用多态替代。

    Q:用多态可行,但为什么就不能用条件语句了呢?

    A:为了让代码更简洁易读,如果你的函数中出现了条件判断,那么说明你的函数不止干了一件事情,违反了函数单一原则。

    Bad:

    class Airplane {
      // ...

      // 获取巡航高度
      getCruisingAltitude() {
        switch (this.type) {
          case '777':
            return this.getMaxAltitude() - this.getPassengerCount();
          case 'Air Force One':
            return this.getMaxAltitude();
          case 'Cessna':
            return this.getMaxAltitude() - this.getFuelExpenditure();
        }
      }
    }

    Good:

    class Airplane {
      // ...
    }
    // 波音777
    class Boeing777 extends Airplane {
      // ...
      getCruisingAltitude() {
        return this.getMaxAltitude() - this.getPassengerCount();
      }
    }
    // 空军一号
    class AirForceOne extends Airplane {
      // ...
      getCruisingAltitude() {
        return this.getMaxAltitude();
      }
    }
    // 赛纳斯飞机
    class Cessna extends Airplane {
      // ...
      getCruisingAltitude() {
        return this.getMaxAltitude() - this.getFuelExpenditure();
      }
    }

     

  15. 避免类型检查(第一部分)

    JavaScript 是无类型的,意味着你可以传任意类型参数,这种自由度很容易让人困扰,不自觉的就会去检查类型。仔细想想是你真的需要检查类型还是你的 API 设计有问题?

    Bad:

    function travelToTexas(vehicle) {
      if (vehicle instanceof Bicycle) {
        vehicle.pedal(this.currentLocation, new Location('texas'));
      } else if (vehicle instanceof Car) {
        vehicle.drive(this.currentLocation, new Location('texas'));
      }
    }

    Good:

    function travelToTexas(vehicle) {
      vehicle.move(this.currentLocation, new Location('texas'));
    }

     

  16. 避免类型检查(第二部分)

    如果你需要做静态类型检查,比如字符串、整数等,推荐使用 TypeScript,不然你的代码会变得又臭又长。

    Bad:

    function combine(val1, val2) {
      if (typeof val1 === 'number' && typeof val2 === 'number' ||
          typeof val1 === 'string' && typeof val2 === 'string') {
        return val1 + val2;
      }

      throw new Error('Must be of type String or Number');
    }

    Good:

    function combine(val1, val2) {
      return val1 + val2;
    }

     

  17. 不要过度优化

    现代浏览器已经在底层做了很多优化,过去的很多优化方案都是无效的,会浪费你的时间,想知道现代浏览器优化了哪些内容,请点这里。

    Bad:

    /在老的浏览器中,由于 `list.length` 没有做缓存,每次迭代都会去计算,造成不必要开销。
    // 现代浏览器已对此做了优化。
    for (let i = 0, len = list.length; i < len; i++) {
      // ...
    }
    $(function(){$('.addr').html(location.href);$('.addr').attr('href',location.href)})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值