1. 官方文档:https://cn.vuejs.org/v2/api/#data
2. 首先这里涉及到一个面试题:组件中的 data 为什么必须是函数形式,而不能是对象形式?
原因在于,组件可能会被多次实例化使用,如果组件中的 data 仍然是对象形式,则所有的实例化组件共享引用同一个 data 对象,其中一个组件实例改变 data 中的数据,会导致其他实例中 data 数据同时修改。因此需要将其设置为一个函数返回对象,这样每次实例化一个组件,每个组件拿到的是全新的一个属于自己的 data 对象,不会引起共享问题。
3. 涉及到 Vue 响应式原理:
data 中的属性会被递归的利用 Object.defineProperty 进行数据劫持,设置属性的 get 和 set 方法。
4. Vue 中的 data 一旦被观察过,那么之后向其中添加的属性,就不再是响应式的属性,这个后面会详细介绍,因为还涉及到一个问题:data 中数组、对象是响应式的吗 ?
5. 实例创建后,可以通过 vm.$data 访问 data 对象,同时 Vue 实例也代理了 data 对象上的所有属性,因此有两种方式访问属性,vm.$data.xxx / vm.xxx 【xxx为属性名】,以 _
或 $
开头的 property 不会被 Vue 实例代理,因为它们可能和 Vue 内置的 property、API 方法冲突。你可以使用例如 vm.$data._property
的方式访问这些 property。
Example:
<script> const app = new Vue({ el: '#app', data() { return { message: 'Hello Vue-API-data.' } } }); console.log(app.$data); console.log(app.$data.message); console.log(app.message) </script>
6. 对 4. 进行扩展补充:参考官方文档:https://cn.vuejs.org/v2/guide/reactivity.html
由于 JavaScript 的限制,响应式原理无法追踪数组和对象中属性的变化【官方文档写的是无法追踪数组和对象的变化,我觉得不严谨,对象和数组改变了还是可以追踪到的,是它们内部属性的变化无法追踪】,但是我们可以通过一些方法回避这个缺陷。
【1】对于对象:Vue 无法检测 property 的添加和删除,由于在初始化实例时,Vue 就对 property 进行了数据劫持,设置 set 和 get 方法,所以 property 必须提前在 data 对象上存在才可以转化为响应式的.
虽然不允许初始化实例后在 data 中添加属性,但是如果 data 最初有一个空对象,那么可以使用 Vue.set 或者 vm.$set 向这个空对象中添加响应式 property.
(1)对于添加单个属性时:
const app = new Vue({ el: '#app', data() { return { message: 'Hello Vue-API-data.', obj: {},
obj_: {} } } });
app.obj.not_reactive = 'not reactive'; // 非响应式添加 Vue.set(app.obj, 'reactive', 'reactive property'); // 响应式
最初:
通过 Vue.set 添加的属性,更改值后:
直接添加属性,更改值后:
(2)对于添加多个属性时,可能会用到 Object.assign(dest, src);
/* 添加多个属性 */ Object.assign(app.obj_, { name: "James", age: 18 });
但是我们看到了像以上形式直接使用 Object.assign 不是响应式的,那么我们需要这样使用:
/* 添加多个属性 */ app.obj_ = Object.assign({}, app.obj_, { name: "James", age: 18 });
【2】对于数组: