首页 > 解决方案 > VUE - 数据对象总是作为引用传递还是有时被复制?

问题描述

我在VUE中有一个概念相关。

我对如何将数据传递给子 vue 文件有点困惑。(vue 实例?老实说不熟悉这个词)

  1. 在某些情况下,通过 'props' 传递数据时,子 vue 文件中的数据更改不会更改父级的数据。

  2. 另一方面,子 vue 文件中的数据变化,实际上是改变了父母的数据。

我刚刚遇到了情况2。也就是数据通过eventbus的时候。

我可以这样理解这种性质吗?

“数据仅在通过事件总线传递时作为参考传递”

尽管,

“当数据通过道具传递时,数据作为单独的副本传递给孩子,并且孩子中的更改不会改变父母中的原始数据”

我能在路上看到 Vue 的本质吗?如果有人能给我一个例子,孩子的变化不会影响父母的数据,那将非常感激。

每次我问与 Vue 相关的问题时,我总是感到非常内疚,因为代码超长,与 Javascript 问题不同。先感谢您。

我刚刚遇到的例子如下。

=main.js=

import Vue from 'vue'
import App from './App.vue'

export const serverBus = new Vue()
new Vue({
  el: '#app',
  render: h => h(App)
})

=服务器.vue=

<template>
    <div class="col-xs-12 col-sm-6">
        <ul class="list-group">
            <Server v-for='server in serverinfo' :serverinfo='server' :key='server.id'></Server>
        </ul>
    </div>
</template>

<script>

import Server from './server.vue'

export default {

 components: {
        Server
    },

data() {
    return {
                serverinfo: [
                {id:1, servno:'#1', servstat:'normal'},
                {id:2, servno:'#2', servstat:'critical'},
                {id:3, servno:'#3', servstat:'unknown'},
                {id:4, servno:'#4', servstat:'error'},
                {id:5, servno:'#5', servstat:'excellent'}]
               }
              }

    }



</script>

<style>

</style>

=服务器.vue=

<template>
  <li class='list-group-item' @click='serverselected'>
      Server {{serverinfo.servno}}
  </li>
</template>

<script>
import {serverBus} from '../../main.js'
export default {
    props:['serverinfo'],

    methods:{
        serverselected(){
            serverBus.$emit('serverselected', this.serverinfo)
        }
    }

}
</script>

<style>

</style>

=ServerDetails.vue=

<template>
    <div class="col-xs-12 col-sm-6">
        <p v-if='!server'>Please Select a server</p>
        <p v-else>Server {{server.servno}} is selected. Status:{{server.servstat}}</p>
        <button class="btn btn-primary" @click='backtonormal'>Back to Normal</button>
    </div>

</template>

<script>
import {serverBus} from '../../main.js'

export default{
    methods:{
        backtonormal(){
            this.server.servstat='normal'
        }
    },

    data(){
        return{
        server:null
              }
    },

    created(){
        serverBus.$on('serverselected',(server)=>{
            this.server=server
        })
    }

}
</script>

<style>

</style>

标签: javascriptvue.jsdata-visualization

解决方案


当你通过 props 传递对象时,Vue 不会复制。如果您通过道具传递一个对象,那么两个组件将看到同一个对象。由于它是同一个对象,因此子对象所做的任何属性更改也会影响另一个父对象。

查看有关单向数据流的文档:

https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

开头的段落有点误导,可能会让您相信副本已被复制。它专门谈论为道具分配新值,但措辞含糊不清。然而,事实并非如此,关键句在最后:

请注意,JavaScript 中的对象和数组是通过引用传递的,因此如果 prop 是数组或对象,则在子组件内改变对象或数组本身影响父状态。

我不知道不复印的官方原因是什么,但一些可能的原因是:

  1. 复制会导致性能损失。
  2. 在代码依赖于对象相等的情况下,它可能会导致错误。
  3. 在所有情况下,复制在技术上是不可能的。可以复制简单的、对 JSON 友好的数据,但一般来说,JavaScript 有几个无法可靠复制的结构,例如带有闭包的函数。

至于你关于发射的问题......

发出变更事件是单向数据流和数据所有权的一部分。这个想法是只有数据的所有者才能修改它。其目的是使推理和调试问题变得更容易。

实际上,正如您所描述的那样,没有什么可以阻止孩子直接修改对象。您将需要自行决定什么最有利于代码的可维护性。

一个问题是孩子与父母耦合。仅当该对象是该数据的最终真实来源时,修改子对象中的对象才有效。例如,如果对象是使用计算属性在父级中创建的,那么修改它将不起作用。通过使用$emit,我们将责任传递给数据的所有者,以决定正确的方式来进行所需的更改。


推荐阅读