1.vue中的MVVM
在Vue框架中,MVVM是指Model-View-ViewModel(模型-视图-视图模型),是一种用于构建用户界面的架构模式。MVVM将用户界面分为三个主要部分:
1)模型(Model):表示应用程序中的数据和业务逻辑,对应vue中data中的数据
2)视图(View):表示用户界面,对应vue中的模板
3)视图模型(ViewModel):连接模型和视图,充当桥梁,对应Vue实例对象

MVVM,最核心的就是 ViewModel
。ViewModel
包含 DOM Listeners
和 Data Bindings
。
Data Bindings
用于将数据绑定到 View
上显示,DOM Listeners
用于监听操作。
- 从
Model
到View
的映射,也就是Data Bindings
。这样可以大量省略我们手动update View
的代码和时间。 - 从
View
到Model
的事件监听,也就是DOM Listeners
。这样我们的Model
就会随着View
触发事件而改变。数据的请求和视图的请求完全解耦(相互影响)。
vue虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm
(ViewModel 的缩写) 这个变量名表示 Vue 实例。
<!--视图 - vue模板容器-->
<div id='root'>
<h1>{{ name }}</h1>
<h1>{{ msg }}</h1>
</div>
<script>
//视图模型 - Vue实例对象
const vm = new Vue({
el: '#root',
data: { // 模型 - data中的数据
name: 'Vue',
msg: 'hello vue'
}
});
console.log(vm)
</script>
注:
1)data中的所有属性,最后都出现在vm身上。
2)vm身上所有的属性和vue原型上所有的属性,在vue模板中都可以直接使用。
数据的双向绑定:
- 一是将模型转换成视图,即将后端传递的数据转换成看到的页面。 实现方式是:数据绑定。
- 二是将视图转换成模型,即将看到的页面转换成后端的数据。实现的方式是:DOM 事件监听。
2. Object.defineProperty
1)Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
2)语法:Object.defineProperty(obj, prop, descriptor)
- obj:要定义属性的对象
- prop:要定义或修改的属性的名称。
- descriptor:要定义或修改的属性配置项。
3)descriptor 里面的可配置项
默认不可枚举,不可修改,不可删除。
let person = {
name: '张三',
sex: '男',
// age: 18
}
//定义的属性默认不可枚举,不可修改,不可删除
Object.defineProperty(person, 'age', {
value: 18
});

高级配置 get( ) 和 set( ) :
let number = 18;
let person = {
name: '张三',
sex: '男',
// age: 18
}
//定义的属性默认不可枚举,不可修改,不可删除
Object.defineProperty(person, 'age', {
//value: 18,
//enumerable: true, //控制属性是否可枚举(遍历),默认false
//writable: true, //控制属性是否可写(修改),默认false
//configurable: true, //控制属性是否可配置(删除),默认false
//当读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get() {
console.log('读取了age属性')
return number;
},
//当修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值value
set(value) {
console.log('修改了age属性,值为',value)
number = value;
}
});
console.log(person.age)
person.age = 30;
console.log(person.age)

注意:
- value 和 get 是同一个作用,只能同时用一个。
- writable 和 set是同一个作用,用一个。
3. 数据代理
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)。
比如:obj 中有一个 x 属性,如果想在 obj2 中也能访问和修改这个属性就可以使用数据代理:
//数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
let obj = { x: 100 };
let obj2 = { y: 200 };
Object.defineProperty(obj2, 'x', {
get() {
return obj.x;
},
set(value) {
obj.x = value;
}
});

4.vue中的数据代理
1)vue中的数据代理
通过vm实例对象来代理data对象中属性的操作(读/写)。在Vue中,数据代理是一种使得在组件中直接通过Vue实例对象来操作data对象中的属性变得可行的机制。Vue实例会对data对象中所有属性进行封装,从而在内部实现对这些属性的访问、修改等操作。
2)基本原理
通过Object.defineProperty()把data对象中所有属性添加到vm上,并给每一个添加到vm上的属性都指定一个getter/setter,在getter/setter内部去操作(读/写)data中对应的属性。
在Vue中,每个Vue实例都有一个与之对应的响应式数据对象。Vue会遍历这个对象所有的属性,并使用Object.defineProperty把这些属性转为响应式属性,这个过程称为数据代理。
实现数据代理的目的是为了让我们可以在Vue实例(或组件实例)上直接访问data对象中的属性。例如,如果你有一个data属性,你可以直接用this.attr
来代替this.data.attr
。
例如如下vue模板:
<div id="root">
<h1>姓名:{{ name }}</h1>
<h1>年龄:{{ age }}</h1>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
name: '张三',
age: 18
}
});
console.log(vm)
</script>
在浏览器控制台打印查看vm实例属性,可以看到:

我们并没有手动的去给name和age属性添加get和set函数,都是vue使用Object.defineProperty()给实例对象vm的data中定义的每个属性都添加了getter和setter。当用户修改data中的属性时,就会自动调用setter改变视图中对应的属性值了,这就是数据代理的实现原理。
在实例化 Vue 对象时,Vue 会将传入的 data 对象的属性都添加到实例的 _data 对象中,并实现数据代理,使得这些属性能够被实例直接访问。如果没有_data对象,那么我们在模版中使用Vue实例中的data属性时,必须要在属性名前面加上_data。
支持