# 开发利器：快速删除一个函数

对于代码佬日常的开发工作中，常常需要把同事或者自己写的一些~~屎山~~代码函数删除；在之前的练习中，我们曾提到过 `p` 这个代指段落的文本对象，所以想到要删除一个函数我们可能会先想到用它来实现，比如 `dap` 如此这般；但因为段落的定义是空行之间的内容为不同段落，这在一些情况下无法满足我们删除一个函数的需求，如：

```js
const test = (a = 1) => {
  console.log(a)
  a = 2
  
  setTimeout(() => {
    console.log(a)
  }, 500);
}
```

我们可以注意到，在函数内部有一个空行，这时我们在空行的上方或者下方使用 `dap`，则只会删除一半的函数。那有没有更好的方法呢？那肯定是有的，不过我们要先来了解一下 `%` 命令和 vim-indent-object。

## `%` - 匹配括号

在 vim 中，我们可以通过 `%` 来匹配括号，即括号 `()`、中括号 `[]`、大括号 `{}`，当我们的光标在括号上时，我们使用 `%` 可以跳到与当前括号成对的另外一个括号上。

## vim-indent-object - vim 缩进对象

这个是 vim 自带的一个扩展插件，该插件基于缩进级别定义了一个新的文本对象 `i`；即我们可以使用它来基于缩进进行一些操作，如 `>ii` 可以把同一个缩进级别的内容全部往右移动一个缩进（中间的 `i` 是指 [`inner`](./day-6.md#语法结构)）。

## 删除函数

通过我们上面提到的两个指令，我们就可以来研究一下怎么删除一下函数了；对于大部分使用缩进的来规范语法结构的语言如 Python 、JavaScript 等，它们的函数也是有着明显的缩进规律的，这时，我们可以使用 `daI` 来实现删除函数，但前提是光标在函数的内部；但如果如下面这种情况：

```js
  const test1 = (a = 1) => {
    console.log(a)
    a = 11
    
    setTimeout(() => {
      console.log(a)
    }, 500);
  }

  const test2 = (a = 2) => {
    console.log(a)
    a = 22
    
    setTimeout(() => {
      console.log(a)
    }, 500);
  }
```

如果光标在 test1 或 test2 函数名那一行并使用 `daI`，则会把两个函数都删除；因为对于这两个函数来说，它们有同样的缩进级别。当然，在大部分情况下，`daI` 都是够用了的；为了让我们用得更顺手一些，我们可以把 `ai` 映射成 `aI`：

```json
  "vim.operatorPendingModeKeyBindings": [
    {
      "before": ["a", "i"],
      "after": ["a", "I"]
    }
  ],
  "vim.visualModeKeyBindings": [
    {
        "before": ["a", "i"],
        "after": ["a", "I"]
    },        
  ]
```

这样我们在可视化模式或者操作待决模式（operator pending mode）时可以直接使用 `i` 代替 `I`。

而为了弥补上面提到的 vim-indent-object 的短板，我们还可以通过 `%` 配合 `<Leader>` 来实现删除函数；首先，对于光标在函数名所在行时（如上面提到的例子），我们可以使用 `V` 来选中当前行，然后需要把光标移动行末，即 `$`，这时光标在花括号上，再键入 `%`，这时候就可以选中到函数的闭合符处，最后键入 `d`，即可把函数删除；总的指令就是 `V$%d`。但是这么长一个命令未免太麻烦，这时我们就可以用 `<Leader>` 来映射：

```json
  "vim.normalModeKeyBindings": [
    {
      "before": ["<Leader>", "d", "f"],
      "after": ["V", "$", "%", "d"]
    },
  ],
```

这样当我们光标在函数名那一行时就可以通过 `<Leader>` + `df` 来快速删除一个函数了。再加上前面提到的光标在函数内部时的删除命令，基本可以应付大部分的情况了。