markdown 使用ES6箭头功能清理Vue模块

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown 使用ES6箭头功能清理Vue模块相关的知识,希望对你有一定的参考价值。

published: true
preview: Recently when refactoring a Vue 1.0 application, I utilized ES6 arrow functions to clean up the code and make things a bit more consistent. Along the way I made a few mistakes and wanted to share the lessons I learned as well as offer a few conventions that I will be using in my Vue applications moving forward.
Recently when refactoring a Vue 1.0 application, I utilized ES6 arrow functions to clean up the code and make things a bit more consistent before updating to Vue 2.0. Along the way I made a few mistakes and wanted to share the lessons I learned as well as offer a few conventions that I will be using in my Vue applications moving forward.

The best way to explain this is with an example so lets start there. I'm going to throw a rather large block of code at you here, but stick with me and we will move through it a piece at a time.

```js
<script>

// require vue-resource...

new Vue({
  
  data: {
      item: {
        title: '',
        description: '',
      }
  },
  
  methods: {
  
    saveItem: function() {
    
      let vm = this;
      
      this.$http.post('item', this.item)
        .then(
        
          function (response) {
            vm.item.title = '';
            vm.item.description = '';
          }, 
          
          function (response) {
            console.log('error', response);
          }
          
        );
    }
    
  }
});
</script>
```

The contrived code sample above would allow you to fill out a small form, and then submit that form to persist a new item to a database. Although this is pretty basic, there are still a few things that I feel could be cleaned up.

## Arrow Functions, and lexical this

Lets start by looking at the `saveItem()` method.

```js
...

saveItem: function() {

let vm = this;

this.$http.post('item', this.item)
  .then(
  
    function (response) {
      vm.item.title = '';
      vm.item.description = '';
    }, 
    
    function (response) {
      console.log('error', response);
    }
    
  );
}

...
```

Something that has always bothered me is the need to assign a temporary variable to hold the value of `this`. The point of assigning `vm = this` is so we can later reference `vm` to get our Vue object. Wouldn't it be nice if we could somehow inherit `this` in those later anonymous functions without having to place it in a temp variable? Thanks to ES6 [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) we can do exactly that.

When we use an arrow function, the `this` is lexical, meaning that it does not create its own `this` context. Instead, `this` has the original meaning from the enclosing context. That means that we can replace our `function (response) {}` callbacks with a much prettier and more terse ES6 arrow function and skip setting up that temporary variable to hold the reference to the Vue object.

```js
...

saveItem: function() {

  // let vm = this;
  
  this.$http.post('item', this.item)
   .then(

    //function (response) => {
    
    response => {
     this.item.title = '';
     this.item.description = '';
    }, 

    //function (response) => {
    
    response => {
     console.log('error', response);
    }
     
   );
}

...
```

Looking better already! Lets keep going.

## Arrow function overkill

If one arrow function is good, more of them must be better right? I mean who doesn't enjoy yanking every single `function() {}` out of their codebase and replacing it with a simple `() => {}`. Looking again at the `saveItem()` method, we could rewrite that using an arrow function to look like this.

```js
...
methods: {
  saveItem: () => {
    this.$http.post('item', this.item)
      .then(
        // callbacks in here
      );
  }
}
...
```

Perfect! Now we have ridded our self of the dreaded `function` and replaced it with our shiny new arrow function syntax. But wait, theres a catch. 

Since arrow functions provide a lexical `this` value, the `this` inside our `saveItem()` refers to the `window` instead of our Vue object which breaks our current implementation! When attempting to get `this.item`, we will actually be looking at `window.item` which is currently `undefined`. 

If only there were another way!

## Method Definitions

As explained [over at MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions), method definitions are shorthand for a function assigned to a method name. Given the following code:

```js
var obj = {
  foo: function() {},
  bar: function() {}
};
```

You are now able to shorten this to: 

```js
var obj = {
  foo() {},
  bar() {}
};
```

Applying that to our `saveItem()` method, we can shorten the definition without having to worry ourselves with that lexical `this` binding that the arrow function was causing.

```js
...
methods: {
  saveItem() {
    this.$http.post('item', this.item)
      .then(
        // callbacks in here
      );
  }
}
...
```

In case it isn't clear, this works for any "top level" functions that are assigned to object keys in our Vue object. You might consider using this for `created` or `data` functions. 

## Speaking of data

In our current code, our `data` key is associated with a plain Javascript `Object`. However, if you have worked with Vue components, you may be aware that when defining a component it is necessary to wrap the returned object in a [closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures). The reason for this is explained in the [the docs]() or this [blog post by Jeff Madsen](http://codebyjeff.com/blog/2016/11/vue-js-simple-tuts-component), but let me just show you what it looks like for now.

```js
...
data: function() {
  return {
    item: {
      title: '',
      description: '',
    }
  }
},
...
```

This is all fine and dandy, but it turns out there is a way to use arrow functions to clean this up a bit. We have already learned that arrow functions provide us with a lexical `this` binding, but they also provide us some options when [defining our function body](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Function_body). In our previous examples we have used "block body" syntax. The second option we have is to provide a "concise body". Let me show you both together so you can see the difference.

```js
var sum = (a,b) => {return a+b;}  // block body syntax, explicit "return" needed
var sum = (a,b) => a+b;           // concise body, implied "return"

var sum = (a,b) => ({sum: a+b});  // returning an object literal requires ()
```

As you can see, if our function is just returning a value, we can exclude the `{}` and `return` and instead just write our return statement. In the last example you can see how returning an object literal has one additional requirement which is a set of `()`. Let's try to apply this to our `data` closure.

```js
// before
data: function() {
  return {
    item: {
      title: '',
      description: '',
    }
  }
},

// after
data: () => ({
    item: {
      title: '',
      description: '',
    }
}),
```

It's a small improvement, but I like the way it looks. Of course you could also use method definition style as well.

```js
// method definition style
data() {
  return {
    item: {
      title: '',
      description: '',
    }
  }
}
```

## Vue ES6 Conventions

With this new found knowledge, I have been using the following conventions when defining my Vue modules.

1. Use [method definitions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions) for all "top level" methods.
2. Use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) for any callbacks inside "top level" methods.
3. Use an arrow function with a ["concise body"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Function_body) for component data closures.

Hopefully these little tips will make writing your Vue modules and components that much more enjoyable and readable. Thanks!

## Footnotes
https://rainsoft.io/when-not-to-use-arrow-functions-in-javascript/

以上是关于markdown 使用ES6箭头功能清理Vue模块的主要内容,如果未能解决你的问题,请参考以下文章

Vue ES6箭头函数使用总结

es6新增在vue中常用语法

vue05-es6模块化和webpack

ES6深入浅出-2 新版函数:箭头函数 2 视频-2.视频 箭头函数杂谈

ES6箭头函数

axios网络请求基本使用配置使用(全局axios和局部axios实例)模块封装axios拦截器