模拟Vue之数据驱动4
| 一、前言 |
在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了。
当然,数组也是对象,也可以通过$set方法实现新增属性。
但是,对于数组而言,通常我们是通过push之类的方法吧。
PS:Vue中明确指出push、pop、shift、unshift、splice、sort、reverse方法为变异方法,可以通过它们监听属性变化,触发视图更新(详情见here)
下面,我们就一起来实现这些Array的变异方法吧。
注:我们将Array变异方法实现,也写在extendObj.js中的,因为数组也是对象嘛。
| 二、Array变异方法实现 |
要实现这些变异方法,毫无疑问,我们会重写它们,那在Array.prototype里面重写吗?
当然不是,这样不就影响了所有数组对象的原型链了么!
为了避免这种情况,且,我们只是想在监听数据对象上继承这些变异数组方法,那么细心的你会发现,其实与我们在"模拟Vue之数据驱动3"中实现$set方法类似了。
首先,我们创建arrKeys对象用于保存需要变异的数组方法以及恒定对象extendArr,如下:
let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
const extendArr = [];
接着,就是在extendArr对象上,一一监听arrKeys中的方法了,与$set方法类似,整体结构如下:
!function(){
arrKeys.forEach(function(key){
proxyObject(extendArr, key, function(){
//TODO
});
});
}();
注:proxyObject方法其实核心就是Object.defineProperty,详见"模拟Vue之数据驱动3".
接下来,就是实现核心部分代码了,重写这些方法的目的,是为了监听数据变化,所以要在方法原有功能不变的情况下,重写它们,Array.xxx.apply即可实现原有功能。
且,push、unshift、splice这三个方法可以在原数组中,新增属性,故而,我们需要监听新增属性以及它们的属性值,这里就和$set方法完全一样了,通过$Observer,即可利用observe以及convert方法实现了。
实现代码如下:
!function(){
arrKeys.forEach(function(key){
proxyObject(extendArr, key, function(){
console.log('Fun ' + key + ' is observed');
let result;
let arrProto = Array.prototype;
let ob = this.$Observer;
let arr = arrProto.slice.call(arguments);
let inserted;
let index;
switch(key){
case 'push': {
inserted = arr;
index = this.length;
break;
}
case 'unshift': {
inserted = arr;
index = 0;
break;
}
case 'splice': {
inserted = arr.slice(2);
index = arr[0];
break;
}
}
result = arrProto[key].apply(this, arguments);
if(inserted){
inserted.forEach(val => {
ob.observe(val);
ob.convert(index++, val);
});
}
return result;
});
});
}();
代码稍长,请自行打开
最后,就是在需要监听的对象上继承这些变异方法咯,如下:
//observer.js
function Observer(data){
if(!(this instanceof Observer)){
return new Observer(data);
}
data.__proto__ = extendObj;
//继承变异方法push、pop等等
if(Array.isArray(data)){
data.__proto__.__proto__ = extendArr;
}
this.data = data;
this.walk(data);
}
好了,一切完毕,接下来就测试下呗:
<script src="./extendObj.js"></script>
<script src="./observer.js"></script>
<script>
'use strict';
let data = {
msg: [5, 2, 0],
user: {
name: 'Monkey',
age: 24
},
lover: {
name: 'Dorie',
age: 23
}
};
Observer(data);
</script>
效果如下:

Perfect,此时,你可能会想,数组方法中仅有push、unshift、splice会为数组新增属性,那么我们又何必将其他方法,例如sort、reverse重写呢,也没发现有什么猫腻呢?
不错,在此时,并没有什么卵用,但是,你要知道sort、reverse等这些方法,可是会引起数组变化的,那么就会影响视图展现,这些变化,又怎么通知数组呢?就是下篇随笔会具体说明的。
该篇随笔代码,详情见github.
模拟Vue之数据驱动4的更多相关文章
- 模拟Vue之数据驱动2
一.前言 在随笔“模拟Vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下: 倘若user中的name.age属性变化,如何知道它们变化了 ...
- 模拟Vue之数据驱动3
一.前言 在"模拟Vue之数据驱动2"中,我们实现了个Observer构造函数,通过它可以达到监听已有数据data中的所有属性. 但,倘若我们想在某个对象中,新增某个属性呢? 如下 ...
- 模拟Vue之数据驱动5
一.前言 在"模拟Vue之数据驱动4"中,我们实现了push.pop等数组变异方法. 但是,在随笔末尾我们提到,当pop.sort这些方法触发后,该怎么办呢?因为其实,它们并没有往 ...
- 模拟Vue之数据驱动
一.前言 在随笔"模拟Vue之数据驱动1"结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下: 倘若user中的name.age属性变化 ...
- 模拟Vue之数据驱动1
一.前言 Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素 ...
- 模拟vue的tag属性,在react里实现自定义Link
我封装了一个简单的实现react里自定义Link的方法,方便大家使用. 因为普通组件没有metch.location.history等属性.只有在<Router>里面的<compon ...
- vue-toy: 200行代码模拟Vue实现
vue-toy 200行左右代码模拟vue实现,视图渲染部分使用React来代替Snabbdom,欢迎Star. 项目地址:https://github.com/bplok20010/vue-toy ...
- vue实现数据驱动视图原理
一.什么是数据驱动 数据驱动是vuejs最大的特点.在vuejs中,所谓的数据驱动就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom. 比如说我们点击一个button,需 ...
- 模拟vue实现简单的webpack打包
一.安装nodejs,查看是否安装成功 二.package.json项目初始化 npm init 电脑有node环境,在根目录下运行命令npm init初始化项目,根据提示输入项目相关信息,然后运行. ...
随机推荐
- VC++.Net CAD编程架构
1.每个对应的菜单项的图形抽象的, 图形抽象基类, 取决于改变来自子(如矩形.椭圆形) 2.在Doc对象管理列表管理,图形对象,当图形需要重绘或序列存储,通过遍历该列表的对象可以是 3. 每个类的职责 ...
- Windows 7硬盘安装CentOS 6.4 双系统 (WIN7硬盘安装Linux(Fedora 16,CentOS 6.2,Ubuntu 12.04))
WIN7下硬盘安装Linux(Fedora 16,CentOS 6.2.Ubuntu 12.04) 近期在看<鸟哥私房菜:基础学习篇>.认为非常不错,想要用U盘装个windows 7 和 ...
- MEF高级进阶
MEF高级进阶 好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四 ...
- 打开VMware的系统出错
打开VMware系统时,出现错误 “Invalid configuration file. File "I:/My Virtual Machines/Windows XP english P ...
- jboss7.1.0配置数据库(mysql)
以jboss7.1.0和mysql为例 1.找到安装目录,我的目录是:jboss-as-7.1.0.CR1b 2.找到standalone.xml,这个文件在我的电脑上是C:\Users\dan\De ...
- java中实现与.net的format格式化字符串输出
Java中的格式化字符串 System.out.println(MessageFormat.format("name={0}", "张三")); .net中的格 ...
- java 命令笔记
http://www.hollischuang.com/archives/105 JPS jps位于jdk的bin目录下,其作用是显示当前系统的java进程情况,及其id号. jps相当于Solari ...
- github 出现 Permission denied (publickey)的解决
从github上clone的时候出现了以下错误 应该是ssh key过期了,试着重新创建ssh key,按以下步骤 1. 注意短横线前后都没有空格 接着一切都默认,它会在把ssh key 储存在 C ...
- MongoDB:利用官方驱动改装为EF代码风格的MongoDB.Repository框架 一
本人系新接触MongoDB不久,属于MongoDB的菜鸟范畴.在使用MongoDB的过程中,总结了一些认识,在此总结跟大家分享.欢迎拍砖. 关于MongoDB的内容,在此就不做介绍了,网上有浩如烟海的 ...
- baidu 200兆SVN代码服务器
转 今天心情好,给各位免费呈上200兆SVN代码服务器一枚,不谢! 开篇先给大家讲个我自己的故事,几个月前在网上接了个小软件开发的私活,平日上班时间也比较忙,就中午一会儿休息时间能抽出来倒腾着去做 ...