浅谈vue原理(一)

  哎,不知道多久之前说的要说说vue原理的,后来就忘记了,嘿嘿,这次就来看看vue的大概原理吧!

  看过我博客的人应该知道,我不是很喜欢用那种太专业的术语的,喜欢用小白都能看懂的话来说,所以可能有的地方表达的不是很专业,不要打我╮(╯_╰)╭

  前提:起码要简单使用过vue,知道怎么用

1.vue的作用  

  首先,我们知道有一个东西叫做mvvm,不懂这个没关系,其实就是简称双向数据绑定,可以拆成三部分,m(model),v(view),vm(viewmodel);

  想一想,假如我们要把html标签中的数据和js中的数据相互产生联系,一般会怎么做?传统的做法就是获取dom节点,然后向其中设置新的值覆盖旧的值就行了,类似下面这样的:

  但是每次都要去获取这个dom节点真的很烦,当html标签很多的时候看找这个节点的选择器都看花了眼,想偷个懒怎么办?最好是在<script>标签中写js代码的地方,有个变量和html标签中的变量是一个共同体,只要修改了其中一个另外一个就会发生变化;

  那么现在的问题就是,怎么将那个变量和html标签中的变量建立联系呢?俗话说得好,解决不了两个对象之间的关系,那就建立一个中间层就好了,如果建立一个还解决不了,那就再建立一个中间层!

  所以这里,我们就需要建立一个中间层来维持js中变量和html中变量的关系,下图所示,那个vue.js文件就是中间层;

  用专业一点的图就是这样的,下图所示;

  现在应该大概懂了啥叫做mvvm了吧!然后我们只需要再深入一下从view->model,然后反着model->view的绑定过程就ok了;两个方向都要看看嘛,所以就叫做双向绑定啊!

2.Object.defineProperty()

  第一次看到这个方法肯定比较懵逼,这方法干嘛的啊?

  我们可以看看这样的一个场景,一个对象let a = { name: 0 },如果我要给这个对象的那么属性修改应该怎么做?我的话,肯定在想,尼玛谁的name居然是0啊肯定写错了,我上去就是一个滑铲就写了a.name = "小王";(牛批!鼓掌╮(╯_╰)╭)

  那么有没有想过a.name="小王"这到底是怎么调用的啊?为啥一个点然后加个属性名就可以给这个对象增加一个属性啊?

  我找了一下,有兴趣的可以参考这个老哥的博客 ,用一句话来说明就是在你声明一个对象的时候,js会偷偷的给这个对象添加一个set和get方法,然后这个方法还不让你看到,只是会在你去a.name的时候会判断后面有没有赋值语句,有的话就调用set方法,没有的话就调用get方法;

  如果有小伙伴学过其他的面向对象的语言的,比如java,应该知道这种get/set方法肯定是我们需要自己生成的,能够实际看得到;

  那么现在又来一个奇葩的场景,在使用a.name="小王"的时候,同时还要打印这样一句话:“呵呵,现在是在修改值哦๑乛◡乛๑”;

  第一种方式,我们可以这样做,手动的去修改a对象去覆盖自带的set方法:

let a = {
      // 加了下划线可以当作私有属性啊(当然,这个不是真正的私有属性啊,有兴趣的可以看看这个博客真正私有属性的实现https://www.cnblogs.com/Mr-O-o-Lee/p/13781362.html)
      _name: 0,
      // 覆盖自带的set方法
      set name(val) {
        console.log('呵呵,现在是在修改值哦๑乛◡乛๑');
        this._name = val;
      }
    }
    a.name = "小王";

  一番波折我们也是完成了,不错不错!但是有没有考虑一个问题,如果这个对象是别人写的呢?你去把别人写的东西给改了......。那么我们有没有什么方法在不修改代码的情况下实现上面的功能呢?

  第二种方法:我们可以使用Object.defineProperty(),我们把上面代码这样修改一下,也是可以的(同理,也可以添加get方法,自己试试;)

let a = {
      _name: 0,
    }
    // 在不改变对象的前提下添加功能
    Object.defineProperty(a, 'name', {
      configurable: true,
      set: (val)=>{
        console.log('呵呵,现在是在修改值哦๑乛◡乛๑');
        _name = val;
      }
    })
    a.name = "小王";

  瞎比比了大半天,终于快把Object.defineProperty()说完了,上面代码中有configurable表示描述属性是否配置,以及可否删除,还有enumerable表示该属性是否能被for in 或者 Object.keys()遍历到;当然还有其他的属性自行了解;

  而vue中就是使用到了Object.defineProperty(),在上面的例子中可以看到,我们可以给一个对象的属性添加get/set方法,在修改属性值的时候,调用set方法中拿到新的值的同时还可以做自定义处理的,专业说法叫做数据劫持。

3.数据代理

  一句话解释清楚什么叫做数据代理:就是将data中的所有数据的地址丢到vue实例中一份,以便于我们可以直接使用vue.xxx去获取属性值vue.data.xxx,伪代码如下:

上面这个图中,假如我们这样写myVue.message="world",实际上调用的是myVue.data.message="world",所以就会触发message属性的数据劫持,调用set方法!

4.手动实现的代码

html部分:

<body>
  <div id="app">
    <h1>{{message}}</h1>
  </div>

  <script src="./mvvm.js"></script>
  <script>
    //1.myVue中不能在data中新增不存在的属性,例如,不能在初始化之后还使用myVue.data.name="小王",变成了下面这样,此时的name没有经过数据劫持
    //2.对于data中属性值的获取或者修改都会触发数据劫持,也就是在初始化的过程中会给的所有属性添加get/set方法

    // 自定义的myVue实例
    let myVue = new MyVue({
      el: '#app',
      data: {
        message: { a: { b: 1 } }
      }
    })
  </script>
</body>

js部分:

function MyVue (options = {}) {
  //第一步:首先就是得到data对象
  this.$options = options;
  this._data = this.$options.data;

  //第二步:数据劫持,将data对象中每一个属性都设置get/set方法
  observe(this._data);

  //第三步:数据代理,这里就是将_data的对象属性放到myVue实例中一份,如果修改属性值实际上修改的还是data中的数据,会触发数据劫持
  for (let key in this._data) {
    //这里的this代表当前myVue实例对象
    Object.defineProperty(this, key, {
      enumerable: true,
      get () {
        return this._data[key];
      },
      set (newVal) {
        this._data[key] = newVal;
      }
    })
  }
}

//数据劫持操作
function observe (data) {
  // 如果data不是对象,就结束,不然递归调用会栈溢出的
  if (typeof data !== 'object') return;
  return new Observe(data);
}

function Observe (data) {
  // 遍历data所有属性
  for (let key in data) {
    let val = data[key];
    //初始化的时候, data中就有复杂对象的时候,例如data: { message:{a:{b:1}}}  ,就需要递归的遍历这个对象中每一个属性都添加get和set方法
    observe(val);
    Object.defineProperty(data, key, {
      enumerable: true,
      get () {
        return val;
      },
      set (newVal) {
        if (val === newVal) return;
        val = newVal;
        //当后续可能因为业务逻辑使得_data.message = {name: "小王"},设置对象类型的属性值,就需要递归的给对象中{name: "小王"}的每个属性也添加get和set方法
        //否则name是没有get/set方法的
        observe(val);
      }
    })
  }
}

 

(0)

相关推荐

  • 浅谈vue原理(四)

    经过了前面这么久,我们已经弄好了数据劫持,数据代理,还通过了发布订阅模式实现了data中数据变化,页面上也会跟着变化: 现在还差点东西,就是当页面上的数据变化的时候,data中的数据也能跟着变化,进而 ...

  • 浅谈vue原理(三)

    上一篇已经实现了发布订阅模式了,现在我们实现从model->view的数据绑定,也就是当data中的数据改变后,页面上的数据也要跟着变化: 1.发布订阅代码的实际应用 我们思考一下,怎么把我们上 ...

  • 什么是环氧磨石地面?浅谈设计原理及方法

    各位设计师 大家好! 室内陆面装修大多会选择铺设环氧磨石 环氧磨石地坪,是模仿水磨石地坪的新型地坪 拥有环氧树脂地坪的所有优异性能 它还可以设计成各种图案. 现设计上的灵活性 俨然成为了室内陆面装修的 ...

  • 浅谈交换机的原理,区别二、三、四层交换机

    大家好,我是瑞哥,今天给大家带来的是交换机的工作原理: 一.交换机的工作原理 二.交换机的三个主要功能 三.交换机的工作特性 四.交换机的分类 五.二.三.四层交换机? 第一种说法: 第二种说法: 第 ...

  • 太 极 反 归 论 ——浅谈太极拳之道原理篇

    有一幅漫画,画的是愚公移山,旁边是这样题词的:"愚公是个不会搬家的倔老头!"其与众不同的意境,迥异于常规的思维,令人若有所思.它意味着对常规观念的挑战.对于具有惯性思维的人们,展示 ...

  • 数字视界|浅谈透明滑轨屏的应用及原理

    浅谈透明滑轨屏的应用及原理,透明滑轨屏主要有订做的滑行轨道.红外感应器.电视.PC.灯箱等部分.透明滑轨屏能够展示很多信息内容,方便客户对产品或者事物的了解,增加趣味性与互动性,因此透明滑轨屏也受大众 ...

  • 浅谈预测的可预测性——预测的三大原理

    去年,或者是前年,朋友推荐,我参加过一次面试.过程中相谈甚欢,谈的具体内容现在大多记不清,但面试结束,一位面试官临走前说了一段话,我记得特别清楚.他说:"你谈了一些需求预测方面的东西,说实话 ...

  • 浅谈C# Dictionary实现原理

    使用C#已经有好多年头了,然后突然有一天被问到C#Dictionary的基本实现,这让我反思到我一直处于拿来主义,能用就好,根本没有去考虑和学习一些底层架构,想想令人头皮发麻.下面开始学习一些我平时用 ...

  • 浅谈robot(机器人)工作原理

    相信许多人在听到机器人这三个字时,会联想到"高级"."炫酷"."变形金刚"."强大",还有一些人会联想到科幻电影中的&q ...