理解 Vue 的 MVVM 模式

MVVM 模式实现

MVVM模式又称双向数据绑定,是数据影响视图,视图影响数据的模式

Vue: 实 现方式使用数据劫持+ 发布订阅模式,其核心为 Object.defineProperty 不兼容IE8以下
Angualr:  使用脏值检测
这次主要介绍 Vue 如何通过 Object.defineProperty() 实现 MVVM

Object.defineProperty(obj, ‘propertyName’, {
    value: Value,
    enumerable: boolean, //默认为fasle 其他属性为不可枚举 无法使用for遍历
    configurable: boolean, //默认false时不能进行删除
    writable: boolean, // 默认为false时无法修改
    // 当有writable和value时不可以使用set get
    //获取obj的值时调用
    get() {
        return 'silverwing'
    },
    //当给obj赋值时调用,参数为赋值的参数
    set(val) {
        console.log(val)
    }
})

数据劫持

使用 Object.defineProperty定义所有属性

Vue 实现 MVVM 的方式主要通过data里面的值 递归的进行数据劫持达到深度响应(因为每次赋予一个新对象时会给这个新对象增加数据劫持)

让我们手动模拟这么一个实现过程:
先创建 一个 html(任意名字) 和 mvvm.js 在同一个目录下

先创建 一个 html(任意名字) 和 mvvm.js 在同一个目录下

*.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        let obj  = {}
        Object.defineProperty(obj, 'school',{
            value:'silverwing'
        })
        
        delete obj.school
    </script>
</body>
</html>


mvvm.js

function Soyas(options = {}) {
    this.$options = options // 将所有属性挂在在了$options
    // this._data
    var data = this._data = this.$options.data;
    observe(data)
}
function observe(data) {
    if (typeof data !== 'object')
        return new Observe(data)
}
// 观察对象增加Object.defineProperty
function Observe(data) { // 这里写主要逻辑
    for (let key in data) { // 把 data 属性 通过Object.defineProperty方式定义属性
        let val = data[key];
        Object.defineProperty(data, key, {
            enumerable: true,
            get() {
                return val;
            },
            set(newVal) { // 更改值的时候
                if (newVal === val) {
                    // 设置的值和旧值一样的时候
                    return;
                }
                val = newVal; // 如果以后获取值的时候将刚才设置的值放回去
            }
        })
    }
}

控制台查看

这样就完成了一个简单的数据劫持

但是任然存在问题

当赋予一个对象时候我们仍需要对内部的对象进行数据劫持,以达到深度响应

如果没有进行数据劫持的情况下,属性不具有 set() get() 方法,此时是无法实现数据相应的

function Observe(data) { // 这里写主要逻辑
    for (let key in data) { // 把 data 属性 通过Object.defineProperty方式定义属性
        let val = data[key];
        observe(val); // 添加劫持
        Object.defineProperty(data, key, {
            ...
            set(newVal){
                ...
                observe(newVal) // 返回对象进行劫持
            }
        })
    }
}

再次查看控制台




如此即可完成数据的每层对象进行劫持达到深度响应的效果

此时我们还需要做一件事,我们每次通过 soyas._data 这种方式访问并不优雅

我们可以通过数据代理达到 soyas.property 的方式访问

function Soyas(options = {}) {
    ...
    // this 代理了 this._data;
    for (let key in data) {
        Object.defineProperty(this, key, {
            enumerable: true,
            get() {
                return this._data[key];
            },
            set(newVal) {
                this._data = newVal

            }
        })
    }
}

添加完上述代码后




Very Good!一切OK

总结:

——Soyas 类内部 通过调用一个 observe 进行数据劫持到达到双向数据绑定

——达到深度响应我们需要在 Observe 遍历数据,和返回新值时候 递归调用 observe,对每一个对象进行数据劫持

——通过对象的内部使用 Object.defineProperty 使用 this 代理 this._data


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值