Front-end refactoring with VS Code

In daily development, we often encounter the need to refactor, and the "Refactor" menu in VS Code provides us with a wealth of operations. It can help us complete the refactoring work more efficiently.

However, the operations provided by this menu are different each time. If you use it temporarily, it will bring some troubles. Therefore, there are often students who dare not touch this refactoring function.

Here, some commonly used operations are summarized for your reference.

First, a common rename, warm up!

Rename

Why rename: The naming is not clear enough for people to understand.

Steps:

  1. Select the variable name, right-click to select 重命名符号(Rename Symbol), or use shortcut keys F2 ;
  2. Enter the name you want to modify in the pop-up box;
  3. VSCode will change all subsequent related names.

image-20220302194921502.png

The warm-up is over, let's get to the point!

refactoring operation

image-20220302140642013.png

  1. Select the content to be reconstructed, right-click to select 重构(Refactor), or use Ctrl + Shift + R.

  2. Depending on what is selected, the following options may appear for refactoring:

    • import/export

      • Convert default export to named export
      • Convert named export to default export
      • Convert namespace import to named export
      • Convert named imports to namepace export
    • function/class

      • Move to a new File
    • variable/expression

      • Extract constant
      • constant extracted to the enclosing scope
      • Constant extracted to Module scope
      • Convert to optional chain expression
      • remove unused declarations
      • before unused declaration
    • string

      • Convert to template string Convert to template string
    • expression/function

      • Extract function
      • The inner function extracted into the current function
      • Functions extracted to Module scope
      • function extracted to global scope
    • 对象方法

      • generate ‘get’ and ‘set’ accessors 生成get、set处理器
      • generate ‘get’ and ‘set’ accessors 生成get、set处理器
      • 将函数转换成 ES2015类
      • 将所有函数转换成类
      • 提取到 class 'xxx' 中的 Method
      • 提取到 class 'xxx' 中的 readonly field

魔法数字

为什么要修改魔法数字?因为除进制数之外,数字的实际意义无法被人看懂。

目标:定义一个常量值,写清楚改数字的实际意义。

操作:

  1. 选中魔法数字进行重构。根据需要,推荐选择:
    • 提取到封闭范围的 constant
    • 提取到 Module/global 范围的 constant
    两者都会定义一个常量,前者定义在当前函数内,后者则是整个模块/文件中;
  2. 代码抽取到新的变量中,并出现重命名的输入框;
  3. 使用全大写单词,单词使用“_”间隔。

例子:今年双十一持续13天,计算除双十一促销结束的时间。

function promotionEndDate() {
  return new Date(new Date('2022-11-11').getTime() + 13 * 60 * 60 * 24 * 1000);
}

/**
 * 修改后:
 * 将开始时间 START_DATE,持续的天数 LASTING_DAYS 抽取出来做成变量
 * 如果只有一处使用,则在使用到的函数内定义;
 * 如果多处都有用,可以考虑放在函数外,模块内。
 */
function promotionEndDate() {
    const START_DATE = '2022-11-11';
    const LASTING_DAYS = 13;
    return new Date(new Date(START_DATE).getTime() + LASTING_DAYS * 60 * 60 * 24 * 1000);
}
复制代码

复杂的逻辑条件

为什么要修改复杂逻辑?复杂的逻辑,往往条件判断繁多,阅读难度比较高。

操作:

  1. 选中复杂的逻辑条件进行重构。根据需要,选择:
    • 提取到封闭范围的 constant
    • 提取到当前函数里的 inner function
    • 提取到 Module/global 范围的 function
  2. 代码抽离到一个新的变量/函数中,并出现重命名的输入框;
  3. 使用驼峰命名,使用 is/has 起头,每个单词首字母大写。

例子:返回指定的某个月有多少天

function monthDay(year, month) {
    var day31 = [1, 3, 5, 7, 8, 10, 12];
    var day30 = [4, 6, 9, 11];
    if (day31.indexOf(month) > -1) {
        return 31;
    } else if (day30.indexOf(month) > -1) {
        return 30;
    } else {
        if ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)) {
            return 29;
        } else {
            return 28;
        }
    }
}

/**
 * 修改后
 * 是否闰年在日期处理函数中会经常使用,所以将其提取到当前模块的最外层了
 */
function monthDay(year, month) {
    ...
    if (day31.indexOf(month) > -1) {
        return 31;
    } else if (day30.indexOf(month) > -1) {
        return 30;
    } else {
        if (isLeapYear(year)) {
            return 29;
        } else {
            return 28;
        }
    }
}

function isLeapYear(year) {
    return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
}
复制代码

写了注释的代码片段

更推荐代码即注释的理念。我们写注释之前要想明白为什么需要注释?

  • 如果代码本身已经很清晰,应该删除注释。
  • 如果抽取代码片段,取个合适的名字,能让代码易于阅读,也可以删除注释。

目标:将代码片段抽取出来做成函数,函数以此代码块的具体功能做命名。

操作:

  1. 选择代码块,重构(Refactor)。选择:
    • 提取到当前函数里的 inner function

例子:ajax 请求

function ajax(options) {
  options = options || {};
  options.type = (options.type || 'GET').toUpperCase();
  options.dataType = options.dataType || 'json';
  const READY_STATE = 4;
  const NET_STATUS = {
    OK: 200,
    RIDERCT: 300
  };
  const params = this.formatAjaxParams(options.data);
  let xhr;

  // 创建 - 非IE6 - 第一步
  if (window.XMLHttpRequest) {
    xhr = new window.XMLHttpRequest();
  } else { // IE6及其以下版本浏览器
    xhr = new window.ActiveXObject('Microsoft.XMLHTTP');
  }

  // 连接 和 发送 - 第二步
  if (options.type === 'GET') {
    ...
  } else if (options.type === 'POST') {
    ...
  }
  
  // 接收 - 第三步
  xhr.onreadystatechange = function () {
    if (xhr.readyState === READY_STATE) {
      ...
    }
  };
}

// 修改后
function ajax(options) {
  ...
  let xhr;

  create();
  connectAndSend();
  recieve();

  function create() {...}
  function connectAndSend() {...}
  function recieve() {...}
}
复制代码

过长的函数

功能拆分做成外部函数,再在内部调用。

操作:

  1. 选择代码块重构,选择:
    • 提取到 Module/Global 范围的 function
  2. The code block generates a function with the necessary parameters

Example: In the previous example, the receiving module of ajax can be separated into the function of the module

function ajax(options) {
  ...

  create();
  recieve();
  connectAndSend(options, xhr, params);
}
function connectAndSend(options, xhr, params) {
  if (options.type === 'GET') {
    ...
  } else if (options.type === 'POST') {
    ...
  }
}
复制代码

Duplicate code/too long files

operate:

  1. Select the code block refactoring, select Move to a new file ;
  2. The code will be migrated to the file with the current function/class as the file name; if there are multiple classes/functions, the first class/function will be specified
  3. Expose functions/classes using export;
  4. Use import to import functions/classes in the original file.

Example: Date handling function:

image-20220302191918541.png

After moving to the new file:

image-20220302192102375.png

In index.js, you can also jump to the defined code, but it is not actually introduced.

image-20220302192443818.png

Rename, fix import/export;

image-20220302193939854.png

import/export

default and naming, namespace and naming transformations.

// named
export function nextMonthDay(year, month) {}
​
// default
export default function nextMonthDay(year, month) {}
​
// namepace 
import * as refactor from './refactor';
​
// named
import { nextMonthDay } from './refactor';
复制代码

object method

Generate get and set processors

const person = {
  age: 32
};
​
// 生成get、set处理器
const person = {
  _age: 32,
  get age() {
    return this._age;
  },
  set age(value) {
    this._age = value;
  },
};
复制代码

template string

String concatenation, quickly convert to template string:

class Person{
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }
}
​
// 模板字符串
class Person{
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}
复制代码

kind

Generate get and set handlers , similar to the results of object methods.

The Method extracted to class xxx is similar to the code written in the comments above and extracted from the repeated code.

It will not be repeated here.

Provides ES 2015 class transformations and supports prototype method transformations.

const Person = function() {
  this.age = 32;
};
Person.prototype.getAge = function() {
  return this.age;
}
Person.prototype.setAge = function(value) {
  return this.age = value;
}
​
// ES 2015 类
class Person {
  constructor() {
    this.age = 32;
  }
  getAge() {
    return this.age;
  }
  setAge(value) {
    return this.age = value;
  }
}
复制代码

Summarize

There are many ways to refactor the code, here are some of them. I hope to be helpful.

For the rest of the content, you can click the refactoring menu more when refactoring the code to see if there are any surprises.

Guess you like

Origin juejin.im/post/7070695967577604133