Vue data的数据响应式到底是如何实现的

研究过程

一般形式

data:{ n:0 } :以这样的方式存储数据,vue能够监听其变化吗?显然是不能的。

使用Obj.defineProperty

let data1 = {}

Object.defineProperty(data1, 'n', {
value: 0
})

为什么要使用defineProperty呢?这不是把一般形式复杂化了吗?

引出主角getter setter。

如果我们想对数据监听进行处理呢?(假设修改的数据必须>=0)

let data2 = {}
data2._n = 0

Object.defineProperty(data2,'n',{
  get(){ return this._n },
  set(value){
    if(value<0) return //在此处可以对数据的修改进行操作
    this._n = value
  }
})

使用代理

如果对方直接修改data2._n怎么办?我们让data2变成匿名对象!

let data3 = proxy({ data:{n:0} }) //括号里是匿名对象,无法访问
function proxy({data}){
 const obj = {}
 Object.defineProperty(obj, 'n', {
  get(){
    return data.n
  },
  set(value){
    if(value<0)return
    data.n = value
   }
 })
 return obj // obj 就是代理
}

代理是什么?

  • 对data的属性的读写,全权交给另一个对象obj负责,那么obj就是data的代理
  • data.n不使用,偏要使用obj.n来操作data.n

如果用户自己给匿名对象起了个名字怎么办呢?

MyData = { n:0 }
let data3 = proxy({ data:MyData })
MyData.n = -1
 //成功赋值为-1

这种情况,我们也要进行拦截处理。

//在4.中的proxy函数中加入这几行
let value = data.n
 Object.defineProperty(data, 'n', {
   get(){
     return value
   },
   set(newValue){
     if(newValue<0)return
     value = newValue
   }
 })

这样,我们就对data进行了监听。

data域的一个bug

new Vue({
  data:{
    obj:{
      a:0
    }
  },
  template:`
    <div @click="set">{{ obj.b }}</div>
  `,
  methods:{
    set(){
      this.obj.b = 1
    }
  }
})
  //bug:vue无法监听一开始data域中不存在的obj.b

解决方法:

data的初始化中加入b

data:{
  obj:{
    a:0,
    b:undefined
    //注意,vue中的null和undefined都不会被渲染出来
  }
}

使用Vue.set(this.obj,'b',1)

数组的长度又不固定,怎么提前声明?

  1. 使用Vue.set (不推荐)
  2. 使用this.array.push (被Vue改写过的push,实现了代理和监听)

详见vue文档,变异方法 章节

总结

//看看下面的代码,发现了什么?

let data = proxy({ data:myData5 })
let vm = new Vue({ data: myData })

Vue正是使用了这种代理和监听的设计模式,形成的数据响应式。

流程:声明数据 => 监听数据 => 代理数据 => 返回数据

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

(0)

相关推荐

  • 谈谈对vue响应式数据更新的误解

    对于刚接触vue的同学会经常遇到数据更新了但是模板没有更新的问题,下面将结合vue的响应式特性以及异步更新机制分析常见的错误: 异步更新带来的数据响应式误解 异步数据的处理基本是一定会遇到的,处理不好就会遇到数据不更新的问题,但有一种情况是在未正确处理的情况下也能正常更新,这就会造成一种误解,详情如下所示: 模板 <div id="app"> <h2>{{dataObj.text}}</h2> </div> js new Vue({ el

  • Vue3.0数据响应式原理详解

    基于Vue3.0发布在GitHub上的第一版源码(2019.10.05)整理 预备知识 ES6 Proxy,整个响应式系统的基础. 新的composition-API的基本使用,目前还没有中文文档,可以先通过这个仓库(composition-api-rfc)了解,里面也有对应的在线文档. 先把Vue3.0跑起来 先把vue-next仓库的代码clone下来,安装依赖然后构建一下,vue的package下的dist目录下找到构建的脚本,引入脚本即可. 下面一个简单计数器的DEMO: <!DOCTY

  • 你了解vue3.0响应式数据怎么实现吗

    从 Proxy 说起 什么是Proxy proxy翻译过来的意思就是"代理",ES6对Proxy的定位就是target对象(原对象)的基础上通过handler增加一层"拦截",返回一个新的代理对象,之后所有在Proxy中被拦截的属性,都可以定制化一些新的流程在上面,先看一个最简单的例子 const target = {}; // 要被代理的原对象 // 用于描述代理过程的handler const handler = { get: function (target,

  • vue响应式更新机制及不使用框架实现简单的数据双向绑定问题

    最近看到有些人说vue是双向数据绑定的,有些人说vue是单向数据流的,我认为这两种说法都是错误的,vue是一款具有响应式更新机制的框架,既可以实现单向数据流也可以实现数据的双向绑定. 2 单向数据流与数据双向绑定 单向数据流是指model中的数据发生改变时引起view的改变. 双向数据绑定是指model中的数据发生改变时view的改变,view的改变也会引起model的改变. //这个是单向数据流,改变这个input的value值并不能是data中的text属性发生改变. <input type

  • 使用Vue.set()方法实现响应式修改数组数据步骤

    在页面中显示数组数据时发现了一个问题,当在methods方法中修改数组数据后,虽然数组已经发生改变,但是改变后的数据并没有渲染到页面上.这是因为在VUE中,如果在实例创建之后添加新的属性或者改变属性到实例上,它将不会触发视图更新. 而Vue.set()方法能够确保响应式对象被创建后仍然是响应式的,同时触发视图更新,动态响应数据的变化. 用法如下: Vue.set(object,index,value) object:要更改的数据源(数组或对象) index:数据的索引(第几项) value:修改

  • 稍微学一下Vue的数据响应式(Vue2及Vue3区别)

    什么是数据响应式 从一开始使用 Vue 时,对于之前的 jq 开发而言,一个很大的区别就是基本不用手动操作 dom,data 中声明的数据状态改变后会自动重新渲染相关的 dom. 换句话说就是 Vue 自己知道哪个数据状态发生了变化及哪里有用到这个数据需要随之修改. 因此实现数据响应式有两个重点问题: 如何知道数据发生了变化? 如何知道数据变化后哪里需要修改? 对于第一个问题,如何知道数据发生了变化,Vue3 之前使用了 ES5 的一个 API Object.defineProperty Vue

  • Vue实现双向绑定的原理以及响应式数据的方法

    一.vue中的响应式属性 Vue中的数据实现响应式绑定 1.对象实现响应式: 是在初始化的时候利用definePrototype的定义set和get过滤器,在进行组件模板编译时实现water的监听搜集依赖项,当数据发生变化时在set中通过调用dep.notify进行发布通知,实现视图的更新. 2.数组实现响应式: 对于数组则是通过继承重写数组的方法splice.pop.push.shift.unshift.sort.reverse.等可以修改原数组的方式实现响应式的,但是通过length以及直接

  • 浅谈Vue 数据响应式原理

    前言 Vue的数据响应主要是依赖了Object.defineProperty(),那么整个过程是怎么样的呢?以我们自己的想法来走Vue的道路,其实也就是以Vue的原理为终点,我们来逆推一下实现过程. 本文代码皆为低配版本,很多地方都不严谨,比如 if(typeof obj === 'object')这是在判断obj是否为为一个对象,虽然obj也有可能是数组等其他类型的数据,但是本文为了简便,就直接这样写来表示判断对象,对于数组使用Array.isArray(). 改造数据 我们先来尝试写一个函数

  • Vue.js中provide/inject实现响应式数据更新的方法示例

    vue.js官方文档:https://cn.vuejs.org/v2/api/#provide-inject 首先假设我们在祖辈时候传入进来是个动态的数据,官方不是说如果你传入了一个可监听的对象,那么其对象还是可响应的么? parent父页面: export default { provide() { return { foo: this.fonnB } }, data(){ return { fonnB: 'old word '} } created() { setTimeout(()=>{

  • 茶余饭后聊聊Vue3.0响应式数据那些事儿

    "别再更新了,实在是学不动了"这句话道出了多少前端开发者的心声,"不幸"的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了.既来之则安之,扶我起来我要开始讲了.Vue3.0 为了达到更快.更小.更易于维护.更贴近原生.对开发者更友好的目的,在很多方面进行了重构: 使用 Typescript 放弃 class 采用 function-based API 重构 complier 重构 virtual

随机推荐