javascript - VUE - 数据对象总是作为引用传递还是有时被复制?
问题描述
我在VUE中有一个概念相关。
我对如何将数据传递给子 vue 文件有点困惑。(vue 实例?老实说不熟悉这个词)
在某些情况下,通过 'props' 传递数据时,子 vue 文件中的数据更改不会更改父级的数据。
另一方面,子 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>
解决方案
当你通过 props 传递对象时,Vue 不会复制。如果您通过道具传递一个对象,那么两个组件将看到同一个对象。由于它是同一个对象,因此子对象所做的任何属性更改也会影响另一个父对象。
查看有关单向数据流的文档:
https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
开头的段落有点误导,可能会让您相信副本已被复制。它专门谈论为道具分配新值,但措辞含糊不清。然而,事实并非如此,关键句在最后:
请注意,JavaScript 中的对象和数组是通过引用传递的,因此如果 prop 是数组或对象,则在子组件内改变对象或数组本身会影响父状态。
我不知道不复印的官方原因是什么,但一些可能的原因是:
- 复制会导致性能损失。
- 在代码依赖于对象相等的情况下,它可能会导致错误。
- 在所有情况下,复制在技术上是不可能的。可以复制简单的、对 JSON 友好的数据,但一般来说,JavaScript 有几个无法可靠复制的结构,例如带有闭包的函数。
至于你关于发射的问题......
发出变更事件是单向数据流和数据所有权的一部分。这个想法是只有数据的所有者才能修改它。其目的是使推理和调试问题变得更容易。
实际上,正如您所描述的那样,没有什么可以阻止孩子直接修改对象。您将需要自行决定什么最有利于代码的可维护性。
一个问题是孩子与父母耦合。仅当该对象是该数据的最终真实来源时,修改子对象中的对象才有效。例如,如果对象是使用计算属性在父级中创建的,那么修改它将不起作用。通过使用$emit
,我们将责任传递给数据的所有者,以决定正确的方式来进行所需的更改。
推荐阅读
- css - 悬停时调整 CSS 文本大小会导致同级元素移动
- c# - 为 TreeView 和 TreeViewItem 触发 ContextMenuOpening 事件
- python - 将 pandas df 插入 sqlite3 会插入运行文本,而不是列
- php - PHP Telegram Bot:从另一个 php 文件调用函数导致 500 内部服务器错误
- python - 在python中读取.txt文件
- python-3.x - 如何在 sublime3 中使用 python3?
- javascript - 不能在模块外使用 import 语句@emotion
- pandas - 在满足条件的行上按组获取和修改列
- swift - Swift加载不占整个视图的List,通过计算行高
- django - 创建和保存访问令牌 simplejwt Django