Vue 在创建实例的过程中调用 data 函数
返回数据对象
通过响应式包装后存储在实例的 $data
并且实例可以直接越过 $data 访问属性
这是为了如在 methods 通过 this.xxx 属性就可以访问到 $data 下的 xxx,这是实例上 get 与 set 所实现
const app = Vue.create({
data() {
return {
title: 'This is my TILTE'
}
},
template: `
<h1>{{ title }}</h1>
`
});
const vm = app.mount('#app');
// 这两个其实是同一份数据
vm.$data.title = 'This is your TITLE';
vm.title = 'This is my TITLE';
// 在实例增加一个属性, 在 $data 是没有的
vm.author = 'Xiaoye';
vm.$data.author = 'Xiaoye'; // 虽然这样可以增加,但是没法在 template 渲染出来,因为渲染时是没有
$data 是响应式数据对象
$,,_,这些都是 Vue 提供的内置 API,开发者尽量要避免用这些前缀命名自己的变量和方法名
data 为何必须是一个函数
const App = {
/*
data: { // 这里是会报错,Vue 会检查 data 是否为 function
a: 1
},
*/
data: function(){
return {
a: 1
}
},
template: `
<h1>{{ a }}</h1>
`
}
Vue.createApp(App).mount('#app');
如果 data 可以不是函数,实现一下:
var data = {
a: 1,
b: 2
}
var vm1 = new Vue({
data: data
})
var vm2 = new Vue({
data: data
})
vm1.b = 3;
console.log(vm1, vm2); // {a: 1, b: 3} | {a: 1, b: 3}
function Vue (options) {
this.$data = options.data;
var _this = this;
for(var key in this.$data) {
(function(k){
Object.defineProperty(_this, k, {
get: function() {
return _this.$data[k];
},
set: function(newValue) {
_this.$data[k] = newValue;
}
});
})(key);
}
}
如果两个实例都使用同一个 data 引用。其中一个实例修改了,会影响到另外一个实例,即会被污染。
使用函数每次实例都会执行函数得到一个独一无二的引用,避免数据的污染。
如果使用对象不使用函数,要深拷贝
this.$data = deepClone(options.data);
因为 Object.defineProperty
在 IE8 只支持 DOM,可以使用 __defineGetter__
、__defineSetter__
function Vue (options) {
this.$data = deepClone(options.data);
var _this = this;
for(var key in this.$data) {
(function(k){
_this.__defineGetter__(k, function() {
return _this.$data[k];
});
_this.__defineSetter__(k, function(newValue) {
_this.$data[k] = newValue;
});
})(key);
}
}