Vue.js中计算属性和普通数据之间的差异

时间:2018-03-14 16:49:47

标签: javascript vue.js vuejs2 vue-reactivity

我观察到当来自data()的普通属性和从它派生的计算属性通过事件传递时,前者保持其反应性而后者失去它。

我为它设置了以下测试用例(also as a JSFiddle如果您愿意的话):



const EventBus = new Vue();

Vue.component('comp', {
  data() {
    return {
      arrData: ['a', 'b']
    };
  },
  computed: {
    arrComputed() {
      return this.arrData.map((e) => e.toUpperCase());
    }
  },
  template: `
  <div>
    <div>Original array: {{ arrData }}</div>
    <div>Computed array: {{ arrComputed }}</div>
    <button @click="remove('a')">Remove a</button>
    <button @click="remove('b')">Remove b</button>
    <button @click="pass">Pass through event</button>
    <button @click="reset">Start over soft</button>
    <button @click="resetHard">Start over hard</button>
  </div>`,
  methods: {
    remove(name) {
      name = name.toLowerCase();
      if(this.arrData.indexOf(name) != -1) {
        this.$delete(this.arrData, this.arrData.indexOf(name));
      }
    },
    pass() {
      EventBus.$emit('pass', this.arrData, this.arrComputed);
    },
    reset() {
      this.$set(this.arrData, 0, 'a');
      this.$set(this.arrData, 1, 'b');
    },
    resetHard() {
      this.arrData = ['a','b'];
    }
  }
});

Vue.component('othercomp', {
  data() {
    return {
      items1: [],
      items2: []
    }
  },
  mounted() {
		EventBus.$on('pass', this.receive);
  },
  template: `
  <div>
    <div>Original array: {{items1}}</div>
    <div>Computed array: {{items2}}</div>
  </div>`,
  methods: {
    receive(items1, items2) {
      this.items1 = items1;
      this.items2 = items2;
    }
  }
});

var app = new Vue({
  el: '#app',
  components:['comp', 'othercomp']
})
&#13;
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <comp></comp>
  <othercomp></othercomp>
</div>
&#13;
&#13;
&#13;

计算结果与普通属性有何不同,以便发生这种行为差异?

我从previous question了解到,像这样传递反应性物体是不好的做法,我应该使用吸气剂功能,但是我仍然想知道为什么会出现这种差异。

2 个答案:

答案 0 :(得分:1)

我不希望这会起作用。通过返回map()的结果,您将反应数组的副本传递给另一个组件。此副本不会对原始数组的更改做出反应 - 它是一个完全不同的数组。即使计算属性将在arrData更改时更新,它也不会自动向第二个组件发送另一个事件,告诉它更新它的数据数组。我认为你需要在两个组件上都有一个计算属性 - 你可以用drin方式使用mixin或filter(在这种情况下可能更合适)。

可以在计算函数中触发事件。但这对我来说似乎非常讨厌:

arrComputed() { 
   let newArray = this.arrData.map((e) => e.toUpperCase());
   EventBus.$emit('pass', this.arrData, newArray);
   return newArray
}

答案 1 :(得分:1)

  

我观察到当来自data()和a的普通属性时   从中派生的计算属性通过事件传递,   前者保持其反应性而后者失去它。

对象变量(Array是对象)包含对象的引用(或句柄)。将一个对象变量分配给另一个时,将复制该句柄,并且这两个变量都是一个对象的句柄。一个上的对象操作将被另一个“看到”。

所以

之后
foo = [1];
bar = foo;
foo.push(2);

foobar,因为它们引用相同的对象,将是[1, 2]。传递值的工作方式相同,但使用简单的赋值更容易说明。

应该很清楚

foo = [1];
bar = foo;
foo = [1, 2];

foo分配一个新句柄,因此它不再引用bar所做的同一个数组。

在您的示例中,arrComputed每次arrData更改时都会创建一个新的Array对象。因此,当您传递arrComputed时,您将传递它上次运行时创建的句柄。当arrData更改时,arrComputed会创建一个新的Array对象,但旧句柄的收件人不会得到该对象,并且永远不会更新与其句柄关联的数组。