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模块的主要内容,如果未能解决你的问题,请参考以下文章