一、前言

在"模拟Vue之数据驱动2"中,我们实现了个Observer构造函数,通过它可以达到监听已有数据data中的所有属性。

但,倘若我们想在某个对象中,新增某个属性呢?

如下:

那么岂不是,新增的infor属性,以及它的对象属性,没有得到监听。

此时,应该怎么处理呢?

通过走读Vue源码,发现他是采用另增属性方法$set实现的。

就是说,如果我们采用常规方法为对象增加属性(如上),我们没法得知并监控它,所以,我们为每个对象扩展一个$set方法,用于另增属性使用,即可,如下:

data.user.$set('infor', {msg: 'happy'});

好了,下面,我们就一同实现这个$set方法吧。

二、$set方法实现

首先,我们得创建一个恒定extendObj对象,用于将$set方法绑定在其中。

你可能会想,为什么我们需要一个extendObj对象呢?直接将$set函数赋值给每个需要监听的对象不就完了么?

是的,这样也可以,但是随着需求增长,倘若我们又想为每个监听对象扩展其他方法呢?难道又要去Observer里面为对象,一一赋值?

so,创建恒定extendObj对象,如下:

const extendObj = {};

因为,我们将$set绑定到extendObj中,且让$set为不可枚举型,所以会用到Object.defineProperty,固将其提取出来,作为一个方法如下:

function proxyObject(obj, key, val, enume){
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enume,
writable: true,
configurable: true
});
};

接下来,就是实现$set方法了,整体结构如下:

proxyObject(extendObj, '$set', function(key, val){
//this指向extendObj
if(this.hasOwnProperty(key)){
return;
}else{
/*
TODO:在extendObj中监听key属性,
且,若key属性值为对象,再次监听key属性值
*/
}
});

看到上面的TODO注释,是否似曾相识,不就是是在“模拟Vue之数据驱动2”遇见过的嘛,通过Observer.prototype.convert监听key属性,通过new Observer再次监听key属性值不就完啦。

的确,但是一旦这样做了,不就和上面我们提到的“直接将$set赋予监听对象”问题一样嘛,耦合性太大,且随着需求上涨,不易维护。

固而,在此需要一点小技巧:在observer模块中为每个监听对象赋予一个$Observer属性,其值指向Observer自身实例,如下:

//observer.js
p.walk = function(data){
let keys = Object.keys(data);
keys.forEach( key => {
let val = data[key];
if(typeof val === 'object'){
new Observer(val);
}
this.convert(key, val);
});
//$Observer属性指向Observer自身实例
data.$Observer = this;
}
//新增一个observe方法
p.observe = function(data){
if(typeof data === 'object'){
new Observer(data);
}
}

好了,这样之后,得$set整体实现如下:

proxyObject(extendObj, '$set', function(key, val){
if(this.hasOwnProperty(key)){
return;
}else{
proxyObject(this, key, val, true);
let ob = this.$Observer;
ob.observe(val);
ob.convert(key, val);
}
});

到此,一个简单的$set方法构建完毕。

在上面我们提到,之所以需要一个恒定extendObj对象,是为了更好的代码管理。且,到目前为止,需要监听的对象上并没有扩展$set方法呢,所以,下面的事情就是为了达到以上效果,如下:

//observer.js
function Observer(data){
if(!(this instanceof Observer)){
return new Observer(data);
}
//将监听对象的隐指针指向我们的extendObj对象
data.__proto__ = extendObj;
this.data = data;
this.walk(data);
}

好了,一切完毕,接下来就测试下吧:

<script src="./extendObj.js"></script>
<script src="./observer.js"></script>
<script>
let data = {
user: {
name: 'Monkey',
age: 24
},
lover: {
name: 'Dorie',
age: 23
}
};
Observer(data);
</script>

效果如下:

Perfect,完整代码见github 

模拟Vue之数据驱动3的更多相关文章

  1. 模拟Vue之数据驱动2

    一.前言 在随笔“模拟Vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下: 倘若user中的name.age属性变化,如何知道它们变化了 ...

  2. 模拟Vue之数据驱动4

    一.前言 在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了. 当然,数组也是对象,也可以通过$set方法实现新 ...

  3. 模拟Vue之数据驱动5

    一.前言 在"模拟Vue之数据驱动4"中,我们实现了push.pop等数组变异方法. 但是,在随笔末尾我们提到,当pop.sort这些方法触发后,该怎么办呢?因为其实,它们并没有往 ...

  4. 模拟Vue之数据驱动

    一.前言 在随笔"模拟Vue之数据驱动1"结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下: 倘若user中的name.age属性变化 ...

  5. 模拟Vue之数据驱动1

    一.前言 Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素 ...

  6. 模拟vue的tag属性,在react里实现自定义Link

    我封装了一个简单的实现react里自定义Link的方法,方便大家使用. 因为普通组件没有metch.location.history等属性.只有在<Router>里面的<compon ...

  7. vue-toy: 200行代码模拟Vue实现

    vue-toy 200行左右代码模拟vue实现,视图渲染部分使用React来代替Snabbdom,欢迎Star. 项目地址:https://github.com/bplok20010/vue-toy ...

  8. vue实现数据驱动视图原理

    一.什么是数据驱动 数据驱动是vuejs最大的特点.在vuejs中,所谓的数据驱动就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom. 比如说我们点击一个button,需 ...

  9. 模拟vue实现简单的webpack打包

    一.安装nodejs,查看是否安装成功 二.package.json项目初始化 npm init 电脑有node环境,在根目录下运行命令npm init初始化项目,根据提示输入项目相关信息,然后运行. ...

随机推荐

  1. The Swift Programming Language 中国版

    iSwifting社会的 Swift 兴趣交流群:303868520 iOS 微信公众账号:iOSDevTip Swift 微信公众账号:SwiftDev iSwifting社区 假设你认为这个项目不 ...

  2. hdu4336压缩率大方的状态DP

    Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  3. 发展合作-ASP.Net传递页面之间的值

    在合作开发中,在页面串传值的时候,遇到了一些困难.在网上搜罗了一下,发现好多的传值方式,能够简单地分下面三种. 一. URL传值 原页面的值放到目标页面的URL中.然后通过QueryString方法获 ...

  4. windows phone (26) ApplicationBar应用程序栏

    原文:windows phone (26) ApplicationBar应用程序栏 在应用程序中,如果需要几个按钮或者菜单来执行一些普通的命令,就应该考虑使用ApplicationBar,因为silv ...

  5. GPS 偏移校正(WGS-84) 至(GCJ-02) java版本号以实现

    public class EvilTransform { final static double pi = 3.14159265358979324; // // // a = 6378245.0, 1 ...

  6.  paip.android环境搭建与开发事例

    paip.android环境搭建与开发事例 好长时间没有玩AndROID了..以前常常做ANDROID的,今天决定在下载一个要做个时间设置器 作者Attilax ,  EMAIL:1466519819 ...

  7. 阅读:AirBag Boosting Smartphone Resistance to Malware Infection

  8. 产品经理(五岁以下儿童)myVegas Slots排名上升的秘密

    myVEGAS Slots于AppStore上排名在今年也就是2月份时候飙升,那么什么情况导致这个现象的呢,我们试图通过App Annie的分析给出答案. 上面是myVegas的排名情况,我们能够看到 ...

  9. WPF中的三维空间(1)

    原文:WPF中的三维空间(1) WPF中可以创建三维几何图形,支持3D对象的应用,支持从3D Max等软件将3D文件obj导入设计中,但是目前还不支持将材质同时导入,这样需要在WPF中对3D对象重新设 ...

  10. 用Linux/Unix命令把十六进制转换成十进制(转)

    那天写个脚本,需要把十六进制的数字转成十进制的打出来,发现不知道要怎么弄,搜一下,原来还是很简单的,比用C语言什么的容易多了,就一些现成的命令就解决了. 先列两种简单的方法: 1) echo 自己就能 ...