欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue数据驱动模拟实现2

程序员文章站 2022-05-25 16:33:57
一、前言 在随笔“模拟vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗? 如下:   倘若u...

一、前言

在随笔“模拟vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗?

如下:

 Vue数据驱动模拟实现2

倘若user中的name、age属性变化,如何知道它们变化了呢?

今儿,就来解决这一问题。

通过走读vue源码,发现他是利用observer构造函数为每个对象创建一个observer对象,来监听数据的,如果数据中的属性又是一个对象,那么就又通过observer来监听嘛。

其实,核心思想就是树的先序遍历(关于树,可参考here)。如我们将上述demo中的data数据,图形化一下,就更加明白了,如下:

Vue数据驱动模拟实现2 

好了,理清了大体思路,下面我们就一起来创建一个observer吧。

二、observer构造

observer整体结构如下:

function observer(data){
 //如若this不是observer对象,即创建一个
 if(!(this instanceof observer)){
 return new observer(data);
 }
 this.data = data;
 this.walk(data); 
}

let p = observer.prototype = object.create(null);

p.walk = function(data){
 /*
 todo:监听data数据中的所有属性,
 并查看data中属性值是否为对象,
 若为对象,就创建一个observer实例
 */ 
}

p.convert = function(key, val){
 //todo:通过object.defineproperty监听数据 
}

好了,下面,我们一起来完成walk以及convert方法吧。

-walk-

首先,我们在walk方法中实现对data对象中的所有属性监听,如下:

p.walk = function(data){
 let keys = object.keys(data);
 keys.foreach( key => {
 let val = data[key];
 this.convert(key, val);
 });
}

且,由于属性中可能又会是一个对象,那么,我们就有必要监听它们。

怎么办呢?

如果是个对象,再次利用observer构造函数,处理它不就完了么。

如下:

p.walk = function(data){
 let keys = object.keys(data);
 keys.foreach( key => {
 let val = data[key];
 //如果val为对象,则交给observer处理
 if(typeof val === 'object'){
  observer(val);
 }
 this.convert(key, val);
 });
}

你可能会有这样的疑问,如果直接利用observer处理对象,那么不就与父对象失去关联了么?

然而并没有,因为javascript对于对象是指向地址关系,所以怎么会失去关联呢。

-convert-

对于convert方法,就比较简单了,一如既往就是利用object.defineproperty监听数据,如下:

p.convert = function(key, val){
 object.defineproperty(this.data, key, {
 get: ()=>{
  console.log('访问了'+key+' 值为'+val);
  return val;
 },
 set: (newval)=>{
  console.log('设置了'+key+' 值为'+newval);
  if(newval !== val){
  val = newval;
  }
 }
 });
}

好了,到此,一个简单的observer就构造完成,下面我们就来测试下,是否成功监听了每个属性。

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

效果如下:

Vue数据驱动模拟实现2

perfect,完整代码见github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。