Skip to content

MVVM模型

1. Vue中的MVVM模型

Alt text 其中View: 就是模版,和DOM对应。
Model:就是data, 和Plain JavaScript Objects(一般的js对象,js对象很多这里特指data)对应。
ViewModel: 主要是作为Model和View的桥梁,将Model通过数据绑定到模版上面,监听页面变化来处理Model数据变化, 简称为vm, 它本身就是Vue实例。
观察发现:

  • data中的所有属性都出现在了vm身上。
  • vm身上所有的属性以及Vue原型上的所有属性,在Vue模版中都可以直接使用。比如插值语法里面{{$options}}, {{$emit}}, {{_c}}

观察控制台中Vue实例对象属性:
Alt text

2. 数据代理

2.1 回顾ES6方法Object.defineproperty()

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
语法为:Object.defineProperty(obj, prop, descriptor), 其中参数说明如下:

  • obj: 要定义属性的对象。
  • prop: 要定义或修改的属性的名称。
  • descriptor: 将被定义或修改的属性描述符。属性描述符分为两种形式:数据描述符和存取描述符,且不能混合使用:
    1. 数据描述符:是一个具有值的属性,该值可以是可写的,也可以是不可写的。以下列举一些属性:
      • configurable 值为true或false。只有值为true时,该属性的描述符才能改变,同时该属性也能从对应的对象上删除。默认值为 false。
      • enumerable 值为true或false。只有值为true时,该属性为可枚举属性。默认值为false。
      • value 包含了这个属性的数据值。默认值为undefined。
      • writable 值为true或false。如果为true,属性的值,也就是上面的value,才能被改变。默认值为false。
    2. 存取描述符:是由getter-setter 函数对组成的属性。以下列举一些属性:
      • configurable 值为true或false。只有值为true时该属性的描述符才能改变,同时该属性也能从对应的对象上删除。默认值为false。
      • enumerable 值为true或false。只有值为true时,该属性为可枚举属性。默认值为false。
      • get一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
      • set 一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。

警告

在描述符中不能同时设置访问器(get和set)和数据属性(value和writable)。如果一个描述符已经设置了访问器,那么再设置value或writable会抛出TypeError异常。如果一个描述符已经设置了数据属性,那么再设置get或set也会抛出TypeError异常。

js
let person = {
    name: 'test',
    age: 18
}
Object.defineProperty(person, 'address', {
    value: '成都市'
})
console.log(person)

Alt text 不可枚举的意思就是不能参与遍历属性,比如:

js
console.log(Object.keys(person));
for(let key in person){
    console.log(person[key])
}

Alt text

js
Object.defineProperty(person, 'address', {
    value: '成都市',
    enumerable: true, // 控制属性是否可以枚举,默认为false
    writable: true, // 控制属性是否可以被修改,默认为false
    configurable: true // 控制属性是否可以被删除, 默认为false
})

Alt text 虽然使用Object.defineProperty()添加属性比在data里面直接配置复杂一些,但能够更加灵活精细话控制属性。 以下是使用get/set函数实现:

js
let person = {
    name: 'test',
    age: 18
}
let myAddress = '地球'
let result = Object.defineProperty(person, 'address', {
    // value: '成都市',
    enumerable: true, // 控制属性是否可以枚举,默认为false
    // writable: true, // 控制属性是否可以被修改,默认为false
    configurable: true, // 控制属性是否可以被删除, 默认为false
    // 当读取person的address属性时, get函数(getter)就会被调用,且返回值就是address的值
    get:function getAddress(){ 
        return 'hello'    
    },
    /**
    * 对象内部直接可以定义为get(){
        }
    **/
    set(value){
         myAddress = value   
    }
})
console.log(result)

Alt text

3. 数据代理的理解

数据代理:通过一个对象代理对另外一个对象中属性的操作(读/写)

js
let obj={x:100}
let obj2={y:200}

Object.defineProperty(obj2, 'x', {
    get(){
        return obj.x
    },
    set(value){
        obj.x = value
    }
})
// 可以发现obj的x可以通过obj2来操作obj的x, 这就是一个数据代理

4. Vue中的数据代理

Alt text

  1. Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
  2. Vue中数据代理的好处:更加方便的操作data中的数据
  3. 基本原理:通过Object.defineProperty()把data对象中所有属性都添加到vm上去,为每一个添加到vm的属性都指定一个getter和setter方法,在getter/setter内部去操作(读/写)data中对应的属性。 特殊的说明下,虽然_data是Vue存放data原始数据的地方,但做了特殊处理: Alt text