不好意思!耽误你的十分钟,让MVVM原理还给你

时间在嘀嗒嘀嗒的走着

既然来了就继续看看吧
  • 这篇文章其实没有什么鸟用,只不过对于现在的前端面试而言,已经是一个被问烦了的考点了
  • 既然是考点,那么我就想简简单单的来给大家划一下重点

众所周知当下是MVVM盛行的时代,从早期的Angular到现在的React和Vue,再从最初的三分天下到现在的两虎相争。

无疑不给我们的开发带来了一种前所未有的新体验,告别了操作DOM的思维,换上了数据驱动页面的思想,果然时代的进步,改变了我们许多许多。

啰嗦话多了起来,这样不好。我们来进入今天的主题

划重点

MVVM 双向数据绑定 在Angular1.x版本的时候通过的是脏值检测来处理

而现在无论是React还是Vue还是最新的Angular,其实实现方式都更相近了

那就是通过数据劫持+发布订阅模式

真正实现其实靠的也是ES5中提供的Object.defineProperty,当然这是不兼容的所以Vue等只支持了IE8+

为什么是它

Object.defineProperty()说实在的我们大家在开发中确实用的不多,多数是修改内部特性,不过就是定义对象上的属性和值么?干嘛搞的这么费劲(纯属个人想法)

But在实现框架or库的时候却发挥了大用场了,这个就不多说了,只不过轻舟一片而已,还没到写库的实力

知其然要知其所以然,来看看如何使用

let obj = {};
let song = '发如雪'; 
obj.singer = '周杰伦';  

Object.defineProperty(obj, 'music', {
    // 1. value: '七里香',
    configurable: true,     // 2. 可以配置对象,删除属性
    // writable: true,         // 3. 可以修改对象
    enumerable: true        // 4. 可以枚举
    // ☆ get,set设置时不能设置writable和value,它们代替了二者且是互斥的
    get() {     // 5. 获取obj.music的时候就会调用get方法
        return song;
    },
    set(val) {      // 6. 将修改的值重新赋给song
        song = val;   
    }
});

// 下面打印的部分分别是对应代码写入顺序执行
console.log(obj);   // {singer: '周杰伦', music: '七里香'}  // 1

delete obj.music;   // 如果想对obj里的属性进行删除,configurable要设为true  2
console.log(obj);   // 此时为  {singer: '周杰伦'}

obj.music = '听妈妈的话';   // 如果想对obj的属性进行修改,writable要设为true  3
console.log(obj);   // {singer: '周杰伦', music: "听妈妈的话"}

for (let key in obj) {    
    // 默认情况下通过defineProperty定义的属性是不能被枚举(遍历)的
    // 需要设置enumerable为true才可以
    // 不然你是拿不到music这个属性的,你只能拿到singer
    console.log(key);   // singer, music    4
}

console.log(obj.music);   // '发如雪'  5
obj.music = '夜曲';       // 调用set设置新的值
console.log(obj.music);   // '夜曲'    6

以上是关于Object.defineProperty的用法

下面我们来写个实例看看,这里我们以Vue为参照去实现怎么写MVVM

// index.html
<body>
    <div id="app">
        <h1>{{song}}</h1>
        <p>《{{album.name}}》是{{singer}}2005年11月发行的专辑</p>
        <p>主打歌为{{album.theme}}</p>
        <p>作词人为{{singer}}等人。</p>
        为你弹奏肖邦的{{album.theme}}
    </div>
    <!--实现的mvvm-->
    <script src="mvvm.js"></script>
    <script>
        // 写法和Vue一样
        let mvvm = new Mvvm({
            el: '#app',
            data: {     // Object.defineProperty(obj, 'song', '发如雪');
                song: '发如雪',
                album: {
                    name: '十一月的萧邦',
                    theme: '夜曲'
                },
                singer: '周杰伦'
            }
        });
    </script>
</body>

上面是html里的写法,相信用过Vue的同学并不陌生

那么现在就开始实现一个自己的MVVM吧

打造MVVM

// 创建一个Mvvm构造函数
// 这里用es6方法将options赋一个初始值,防止没传,等同于options || {}
function Mvvm(options = {}) {   
    // vm.$options Vue上是将所有属性挂载到上面
    // 所以我们也同样实现,将所有属性挂载到了$options
    this.$options = options;
    // this._data 这里也和Vue一样
    let data = this._data = this.$options.data;
    
    // 数据劫持
    observe(data);
}
数据劫持

为什么要做数据劫持?

  • 观察对象,给对象增加Object.defineProperty
  • vue特点是不能新增不存在的属性 不存在的属性没有get和set
  • 深度响应 因为每次赋予一个新对象时会给这个新对象增加defineProperty(数据劫持)

多说无益,一起看代码

// 创建一个Observe构造函数
// 写数据劫持的主要逻辑
function Observe(data) {
    // 所谓数据劫持就是给对象增加get,set
    // 先遍历一遍对象再说
    for (let key in data) {     // 把data属性通过defineProperty的方式定义属性
        let val = data[key];
        observe(val);   // 递归继续向下找,实现深度的数据劫持
        Object.defineProperty(data, key, {
            configurable: true,
            get() {
                return val;
            },
            set(newVal) {   // 更改值的时候
                if (val === newVal) {   // 设置的值和以前值一样就不理它
                    return;
                }
                val = newVal;   // 如果以后再获取值(get)的时候,将刚才设置的值再返回去
                observe(newVal);    // 当设置为新值后,也需要把新值再去定义成属性
            }
        });
    }
}

// 外面再写一个函数
// 不用每次调用都写个new
// 也方便递归调用
function observe(data) {
    // 如果不是对象的话就直接return掉
    // 防止递归溢出
    if (!data || typeof data !== 'object') return;
    return new Observe(data);
}

以上代码就实现了数据劫持,不过可能也有些疑惑的地方比如:递归

再来细说一下为什么递归吧,看这个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值