方法vs在Vue中计算

时间:2017-06-04 04:50:09

标签: javascript methods vue.js vuejs2 computed-properties

Vue.js中方法和计算值之间的主要区别是什么?

它们看起来一样可互换。

10 个答案:

答案 0 :(得分:139)

计算值和方法在Vue中非常不同,在大多数情况下绝对不可互换。

计算财产

计算值的更合适的名称是computed property。事实上,当Vue被实例化时,计算属性将被转换为具有getter的Vue属性,有时也会被设置为setter。基本上,您可以将计算值视为派生值,只要更新用于计算它的其中一个基础值,它就会自动更新。你不调用一个计算机,它不接受任何参数。您可以像引用数据属性一样引用计算属性。以下是documentation

中的经典示例
computed: {
  // a computed getter
  reversedMessage: function () {
    // `this` points to the vm instance
    return this.message.split('').reverse().join('')
  }
}

在DOM中引用了这样的内容:

<p>Computed reversed message: "{{ reversedMessage }}"</p>

计算值对于操纵Vue上存在的数据非常有价值。无论何时您想要过滤或转换数据,通常都会为此目的使用计算值。

data:{
    names: ["Bob", "Billy", "Mary", "Jane"]
},
computed:{
    startsWithB(){
        return this.names.filter(n => n.startsWith("B"))
    }
}

<p v-for="name in startsWithB">{{name}}</p>

计算值也会被缓存,以避免重复计算在未更改时不需要重新计算的值(例如,它可能不在循环中)。

方式

方法只是绑定到Vue实例的函数。它只会在您明确调用它时进行评估。像所有javascript函数一样,它接受参数,并在每次调用时重新进行评估。在任何函数都有用的相同情况下,方法很有用。

data:{
    names: ["Bob", "Billy", "Mary", "Jane"]
},
computed:{
    startsWithB(){
        return this.startsWithChar("B")
    },
    startsWithM(){
        return this.startsWithChar("M")
    }
},
methods:{
    startsWithChar(whichChar){
        return this.names.filter(n => n.startsWith(whichCharacter))
    }
}

Vue的documentation非常好并且易​​于访问。我推荐它。

答案 1 :(得分:35)

由于@gleenk要求一个实际的例子来明确方法和计算属性之间的缓存和依赖性差异,我将展示一个简单的场景:

app.js

new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },
    methods: {
        addToAmethod: function(){
            console.log('addToAmethod');
            return this.a + this.age;
        },
        addToBmethod: function(){
            console.log('addToBmethod');
            return this.b + this.age;
        }
    },
    computed: {
        addToAcomputed: function(){
            console.log('addToAcomputed');
            return this.a + this.age;
        },
        addToBcomputed: function(){
            console.log('addToBcomputed');
            return this.b + this.age;
        }
    }
});

这里我们有2个方法和2个计算属性来执行相同的任务。方法addToAmethod&amp; addToBmethod和计算属性addToAcomputed&amp; addToBcomputed全部将+20(即age值)添加到ab。关于这些方法,它们 方法没有改变。对于计算属性,仅在依赖关系发生变化时才执行代码;例如,引用A或B的特定属性值之一将分别触发addToAcomputedaddToBcomputed

方法和计算描述看起来非常相似,但是@Abdullah Khan已经specified它们不是同一个东西!现在让我们尝试添加一些html来一起执行所有内容,看看差异在哪里。

方法案例演示

&#13;
&#13;
new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },
    methods: {
        addToAmethod: function(){
            console.log('addToAmethod');
            return this.a + this.age;
        },
        addToBmethod: function(){
            console.log('addToBmethod');
            return this.b + this.age;
        }
    }
});
&#13;
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>VueJS Methods - stackoverflow</title>
            <link href="style.css" rel="stylesheet" />
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
    
        </head>
        <body>
            <div id="vue-app">
                <h1>Methods</h1>
                <button v-on:click="a++">Add to A</button>
                <button v-on:click="b++">Add to B</button>
                <p>Age + A = {{ addToAmethod() }}</p>
                <p>Age + B = {{ addToBmethod() }}</p>
            </div>
        </body>
        
        <script src="app.js"></script>
    </html>
&#13;
&#13;
&#13;

解释结果

当我点击按钮&#34;添加到A&#34; 时,会调用所有方法(请参阅上面的控制台日志屏幕结果),addToBmethod()也是已执行,但我没有按&#34;添加到B&#34; 按钮;引用B的属性值没有改变。如果我们决定单击&#34;添加到B&#34; 按钮,则会出现相同的行为,因为这两个方法将再次独立于依赖项更改而被调用。根据这种情况,这是不良做法因为我们每次都在执行方法,即使依赖关系没有改变。这实际上是消耗资源的,因为没有用于未更改的属性值的缓存。

method button method

Computed属性案例演示

&#13;
&#13;
new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },

    computed: {
        addToAcomputed: function(){
            console.log('addToAcomputed');
            return this.a + this.age;
        },
        addToBcomputed: function(){
            console.log('addToBcomputed');
            return this.b + this.age;
        }
    }
});
&#13;
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>VueJS Computed properties - stackoverflow</title>
            <link href="style.css" rel="stylesheet" />
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
        </head>
        <body>
            <div id="vue-app">
                <h1>Computed Properties</h1>
                <button v-on:click="a++">Add to A</button>
                <button v-on:click="b++">Add to B</button>
                <p>Age + A = {{ addToAcomputed }}</p>
                <p>Age + B = {{ addToBcomputed }}</p>
            </div>
        </body>
        
        <script src="app.js"></script>
    </html>
&#13;
&#13;
&#13;

解释结果

当我点击&#34;添加到A&#34; 按钮时,只调用计算属性addToAcomputed,因为正如我们已经说过的那样,计算属性被执行仅当依赖关系发生变化时。由于我没有按下按钮&#34;添加到B&#34; 并且B的年龄属性值没有改变,因此没有理由调用和执行计算属性addToBcomputed。因此,从某种意义上说,计算属性是保持&#34;同样不变的&#34; B属性的值就像一种缓存。在这种情况下,这是考虑良好做法

computed button computed

答案 2 :(得分:9)

来自docs

  

..计算属性根据其依赖项进行缓存。计算属性仅在其某些依赖项发生更改时才会重新计算。

如果您希望缓存数据,另一方面如果您不希望缓存数据,请使用Computed属性使用简单的Method属性。

答案 3 :(得分:4)

计算与方法之间的区别之一。假设我们有一个将返回计数器值的函数。(counter只是变量)。让我们看看函数在计算方法

中的行为方式

计算

在第一次执行时,函数内部的代码将被执行,vuejs会将计数器值存储在缓存中(以加快访问速度)。但是,当我们再次调用该函数时,vuejs将不会再次执行该函数内部编写的代码。它首先检查是否对计数器进行了任何更改。如果进行了任何更改,则仅它将重新执行该函数内部的代码。如果未更改计数器,则vuejs将不会再次执行该功能。它只会从缓存中返回先前的结果。

方法

这就像javascript中的常规方法一样。每当我们调用该方法时,它将始终在函数内部执行代码,而不管对计数器所做的更改如何。

方法将始终重新执行代码,而不管代码中的更改如何。仅当其中一个依赖项的值发生更改时,计算的内容才会重新执行代码。否则,它将为我们提供缓存中的先前结果,而无需重新执行

答案 4 :(得分:2)

计算的属性

计算属性也称为计算值。这意味着它们会更新,并且可以随时更改。同样,它会缓存数据直到更改。实例化Vue时,将计算出的属性转换为属性。

我想分享的另一件事,您无法在计算属性中传递任何参数,这就是为什么在调用任何计算机属性时都不需要括号的原因。

方法

方法与函数相同,并且工作方式相同。此外,方法不执行任何操作,除非您调用它。此外,与所有javascript函数一样,它接受参数,并且每次调用时都会重新评估。之后,他们将无法缓存值

在调用括号的方法中,您可以在其中发送一个或多个参数。

答案 5 :(得分:1)

这是该问题的细分。

何时使用方法

  • 对DOM中发生的某些事件做出反应
  • 在组件中发生某些事情时调用函数。
  • 您可以从计算的属性或观察程序中调用方法。

何时使用计算属性

  • 您需要从现有数据源中编写新数据
  • 您在模板中使用的变量是根据一个或多个数据属性构建的
  • 您希望将复杂的嵌套属性名称简化为更易读和易于使用的名称(但是在原始属性更改时进行更新)
  • 您需要引用模板中的值。在这种情况下,最好创建一个计算属性,因为它已缓存。
  • 您需要倾听多个数据属性的变化

答案 6 :(得分:1)

偶然发现了同样的问题。对我来说,这样更清楚:

  1. 当Vue.js看到 v-on directive 后跟一个方法时,它确切地知道要调用的方法何时叫它。
<button v-on:click="clearMessage">Clear message</button> // @click
// method clearMessage is only called on a click on this button

<input v-model="message" @keyup.esc="clearMessage" @keyup.enter="alertMessage" />
/* The method clearMessage is only called on pressing the escape key
and the alertMessage method on pressing the enter key */
  1. 如果在没有v-on directive的情况下调用方法 ,则在每次更新DOM的页面上(每次触发事件时)都会调用 (或者只是需要重新呈现页面的一部分)。即使该方法与事件被触发无关。
<p>Uppercase message: {{ messageUppercase() }}</p>
methods: {
   messageUppercase() {
      console.log("messageUpercase");
      return this.message.toUpperCase();
   }
}
/* The method `messageUppercase()` is called on every button click, mouse hover 
or other event that is defined on the page with the `v-on directive`. So every
time the page re-renders.*/
  1. 当更改了由函数定义中的 this引用的属性值时,仅调用
<p>Uppercase message: {{ messageUppercase }}</p> 
data() {
 return {
    message: "I love Vue.js"
   }
 },
computed: {
 messageUppercase() {
    console.log("messageUpercase");
    return this.message.toUpperCase();
 }
}
/* The computed property messageUppercase is only called when the propery message is
changed. Not on other events (clicks, mouse hovers,..) unless of course a specific 
event changes the value of message.  */

这里的收获是,最好使用computed属性,以防不使用v-on directive调用方法。

答案 7 :(得分:0)

作为一种简单的方式按vueJs文件:

在比较,方法调用将始终运行该函数每当重新渲染发生。

虽然甲计算属性将仅重新评估当一些其反应依赖性已经改变

答案 8 :(得分:0)

在 Vue 3 附带的可作为 vue 2 插件提供的 vue 组合 API 中,方法和计算属性是不同的语法:

示例:

计算:

这是一个函数,默认情况下接受一个 getter 回调作为参数,并根据其他属性(如 ref、reactive 或 store state)返回一个不可变的 ref。

import {computed,ref} from 'vue'

export default{

setup(){
  const count=ref(0);
  
  const doubleCount=computed(()=>count.value*2) 

 return {count,doubleCount} //expose the properties to the template 
 }
}

方法

是纯 javascript 函数,在 Vue 和 vanilla js 中的行为方式相同,它们暴露给模板并用作事件处理程序,它们不应该用于渲染目的,这可能会导致一些问题,例如无限渲染。

import {computed,ref} from 'vue'

export default{

setup(){
  const count=ref(0);
  
  const doubleCount=computed(()=>count.value*2) 
 
  function increment(){
   ref.value++
 }

 return {count,doubleCount,increment} //expose the properties/functions to the template 
 }
}

区别:

计算:

  • 它被评估为不可变属性而不是函数
  • 它观察另一个属性并根据该属性返回一个属性。
  • 不能带参数。
  • 可以使用 watch 属性观看

方法:

  • 用于重构计算/观察者属性或其他函数中的代码
  • 用作事件处理程序
  • 不应在模板内调用它以避免呈现问题。

答案 9 :(得分:0)

我会尽量补充其他成员的答案。这个例子和解释让我完全明白了计算属性的要点。希望看完我的帖子,你也能有所了解。


如果需要更改数据,必须使用方法。当您需要更改现有数据的表示时,您将使用计算属性。当您练习这两个概念时,您将轻松使用它们。以下是一些curial键:

  1. 计算属性必须始终返回一个值;
  2. 计算属性仅用于转换数据,而不用于为我们的表示层更改数据 |他们不应更改或更改现有数据。

正如您已经阅读过的或者在运行我的示例代码之后,您将看到只有计算属性中显示的值发生了 bieng 更改(在方法内部或通过用户输入或通过其他方式),计算属性将被重新计算和缓存。 但是每次调用一个方法时,不管结果如何都会执行它(例如在我的例子中,当一个值达到0值时,不再重新计算计算属性)

在例子中,有一个简单的系统;你在哪里:

  • 拥有现金;
  • 您在银行账户中的现金;
  • 可以从您的银行账户中提款;
  • 可以向某人借一些钱(无限钱)。

new Vue({
  el: '#app',
  data: {
    infinity: Infinity,
    value: 3,
    debt: -6,
    cash: 9,
    moneyInBank: 15,
  },

  computed: {
    computedPropRemainingCashFundsIfPaid: function() {
      console.log('computedPropRemainingCashFundsIfPaid');
      return this.debt + this.cash;
    },
    computedPropRemainingTotalFunds: function() {
      console.log('computedPropRemainingTotalFunds');
      return this.cash + this.moneyInBank + this.debt;
    }
  },
  methods: {
    depositFunds: function(from, to, value, limit = false) {
      if (limit && (this[to] + value) >= 0) { // if you try to return greater value than you owe
        this[from] += this[to];
        this[to] = 0;
      } else if (this[from] > value && this[from] - value >= 0) { // usual deposit
        this[to] += value;
        this[from] -= value;
      } else { // attempt to depost more than you have
        this[to] += this[from];
        this[from] = 0;
      }
    },
    repayADebt: function() {
      this.value = Math.abs(this.value);
      if (this.debt < 0) {
        this.depositFunds('cash', 'debt', this.value, true);
      }
      console.log('Attempt to repayADebt', this.value);
    },
    lendAmount: function() {
      this.depositFunds('infinity', 'debt', -Math.abs(this.value));
      console.log('Attempt to lendAmount', this.value);
    },
    withdraw: function() {
      if (this.moneyInBank) {
        this.depositFunds('moneyInBank', 'cash', this.value);
      }
      console.log('Attempt to withdraw', this.value);
    }
  }
});
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
  overflow-wrap: break-word;
}

html {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana;
  font-size: 62.5%;
}

body {
  margin: 0;
  font-size: 1.6rem;
}

#app {
  margin: 3rem auto;
  max-width: 50vw;
  padding: 1rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
}

label,
input {
  margin-bottom: 0.5rem;
  display: block;
  width: 100%;
}

label {
  font-weight: bold;
}

ul {
  list-style: none;
  margin: 1rem 0;
  padding: 0;
}

li {
  margin: 1rem 0;
  padding: 1rem;
  border: 1px solid #ccc;
}

.grid {
  display: grid;
  grid: 1fr / 1fr min-content 1fr min-content;
  gap: 1rem;
  align-items: center;
  margin-bottom: 1rem;
}

.grid> :is(button, input) {
  height: 3rem;
  margin: 0;
}

.computed-property-desc {
  padding: 1rem;
  background-color: rgba(0, 0, 0, 0.3);
  text-align: justify;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>A First App</title>
  <link rel="stylesheet" href="styles.css" />
</head>

<body>
  <div id="app">

    <h1>Computed Properties Guide</h1>
    <p style="background-color: bisque;">
      Let's assume that you have <span v-once>{{ cash }}</span>$; And you need to pay a debt=<span v-once>{{ debt }}</span>
    </p>
    <p>Your bank account: {{ moneyInBank }}$ <button v-on:click="withdraw(value)">Withdrow {{ value }}$ from
                bank</button></p>
    <p>Your cash: {{ cash }}$</p>
    <p>Your debt: {{ debt }}$ <button v-on:click="lendAmount(value)">Lend {{ value }}$ from Infinity</button></p>
    <div class="grid">
      <button v-on:click="repayADebt(value)">Repay a debt</button>
      <span>in amout of</span>
      <input type="text" v-model.number="value">
      <span>$</span>
    </div>

    <p>computedPropRemainingCashFundsIfPaid/<br><mark>Available funds in case of debt repayment</mark> = {{ computedPropRemainingCashFundsIfPaid }}$</p>
    <p>computedPropRemainingTotalFunds = {{ computedPropRemainingTotalFunds }}$</p>

    <p class="computed-property-desc">when you need to change data, you will use methods. And When you need to change the presentation of existing data, you will use computed properties. As you practice both concepts, it will become easier which one should you use. Very important notes:
      1. it must always return a value; 2. computed properties are only used for transforming data and not for chaning it for our presentation layer | they should not alter or change the existing data</p>

  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
</body>

</html>