Object.defineProperty()

得力于 Object.defineProperty() 的特性,vue 的数据变化有别于 react 和小程序,是非侵入式的。详细介绍可以看 MDN 文档,这里特别说明几点:

  • get / set 属性是函数,出于习惯会被称为 getter 函数 / setter 函数(Java,c 中都有这种惯例)
  • value 或 writable 和 get 或 set 是不能同时出现的,否则报错
  • 注意区别 Object.defineProperties()

定义 defineReactive 函数

Object.defineProperty() 在使用 getter 和 setter 的时候,要想实现属性的修改,需要借助一个变量周转,如下面的 value,这就很麻烦。

const obj = {}
let value
Object.defineProperty(obj, 'a', {
  enumerable: true,
  configurable: true,
  get() {
    console.log('getter')
    return value
  },
  set(newValue) {
    value = newValue
    console.log('setter', newValue)
  }
})

所以定义了 defineReactive 函数,方便去给对象增加一个响应式属性。这里创建一个闭包的环境:闭包一定要有内外两个函数,外面这个函数 defineReactive 的 value 就形成了闭包。

const obj = {}
function defineReactive(data, key, value) {
  // 如果只传了两个参数,则让 value 直接等于 data[key]
  if (arguments.length === 2) value = data[key]

  Object.defineProperty(data, key, {
    enumerable: true, // 可被枚举(for...in 或 Object.keys 方法)
    configurable: true, // 可被配置,比如删除
    get() {
      console.log('查看了'   key   '属性')
      return value
    },
    set(newValue) {
      console.log('修改了'   key   '属性')
      value = newValue
    }
  })
}

defineReactive(obj, 'a', 10)
console.log(obj.a)
obj.a = 11
console.log(obj.a)

得到的结果如下图:

递归侦测对象的全部属性

我们自己写一个能够侦测对象全部属性的库
新建 index.js 作为主入口文件,用于测试效果,我们 let 一个对象 obj,目标是通过把 obj 作为参数传给 observe 函数,即可实现对 obj 对象所有属性的查看与修改的监测。

// index.js
import observe from './observe.js'
let obj = {
  a: {
    m: {
      n: 1
    }
  },
  b: 2
}
observe(obj)

流程分析

observe 函数

observe 函数用于观察一个对象(value)的属性是否已被监测的(是否有 __ob__ 属性),如果不是则让其属性成为响应式的(通过 new Observer(value))。
注意:之所以起了 __ob__ 这么奇怪的变量名,是为了保证不会与对象的原有属性同名。

// observe.js
import Observer from './Observer.js'
export default (value) => {
  if (typeof value !== 'object') return
  if (value.__ob__ !== undefined) {
    // 暂时留空
  } else {
    new Observer(value)
  }
}

Observer 类

Observer 是一个类,一旦 new 了一个实例,则做 2 件事:

  • 给传入的 value(其实是个对象) 添加 __ob__ 属性,值为这次 new 的实例(也就是构造函数中的 this),因为希望 __ob__ 属性是不可被枚举的,所以用 def 函数处理。
  • 遍历 value 的属性,通过 defineReactive 函数将其变为响应式的
// Observer.js
import { def } from './utils.js'
import defineReactive from './defineReactive.js'

export default class Observer {
  constructor(value) {
    def(value, '__ob__', this, false)
    this.walk(value)
  }
  // 处理对象,让对象的属性变为响应式
  walk(value) {
    for (let key in value) {
      defineReactive(value, key)
    }
  }
}

def 函数定义如下:

export const def = (obj, key, value, enumerable) => {
  Object.defineProperty(obj, key, {
    value,
    enumerable,
    writable: true,
    configurable: true
  })
}

完善 defineReactive 函数

相较于前面定义的时候,在两个地方添加了 observe(value),从而实现了递归侦测对象的全部属性。这里的参数 value,就是已经被变为响应式的属性的值,这个值如果是个对象,也需要被侦测,所以也要被 observe。

// defineReactive.js
import observe from './observe.js'

export default function defineReactive(data, key, value) {
  if (arguments.length === 2) value = data[key]

  // 注意这里不是传 key 而是传 value,因为 key 只是一个字符串,value 才是 key 指向的对象
  observe(value)
  // 让 data 的 key 属性变为响应式属性
  Object.defineProperty(data, key, {
    enumerable: true, 
    configurable: true, 
    get() {
      console.log('查看了'   key   '属性')
      return value
    },
    set(newValue) {
      console.log('修改了'   key   '属性')
      value = newValue
      // 修改的属性也需要被观察,如果是对象需要被侦测
      observe(newValue)
    }
  })
}

至此,在 index.js 传入 observe 的 obj 的每个属性都是响应式的了

// index.js
...省略前面的代码
obj.a.m = {
  y: 8
}
console.log(obj.a.m.y)

测试结果如下:

One More Thing

普通对象也是有 getter 和 setter 的:

  • get propertyName(){} 用来得到当前属性值的回调函数
  • set propertyName(){} 用来监视当前属性值变化的回调函数
  • 下面的代码中,属性 a 称为“数据属性”,它只有一个简单的值;属性b这种用 getter 和 setter 方法定义的属性称为“存取器属性”。
var num= {
    a: 2,
    get b(){
        return 2
    }
}

存取器属性定义为一个或两个与属性同名的函数,这个函数定义不使用 function 关键字,而是使用 get 或 set,也没有使用冒号将属性名和函数体分开。

到此这篇关于vue.js数据响应式原理解析的文章就介绍到这了,更多相关vue.js响应式原理 内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

vue.js数据响应式原理解析的更多相关文章

  1. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  2. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  3. 如何在PHP环境中使用ProtoBuf数据格式

    这篇文章主要介绍了如何在PHP环境中使用ProtoBuf数据格式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

  4. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  5. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  6. Android本地存储方法浅析介绍

    这篇文章主要介绍了Android本地存储案例,方法简单可以实现存储并达到节省内存的效果,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  7. 详解Python如何实现Excel数据读取和写入

    这篇文章主要为大家详细介绍了python如何实现对EXCEL数据进行读取和写入,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. Python自动化办公之Excel数据的写入

    这篇文章主要为大家详细介绍一下Python中excel的写入模块- xlsxwriter,并利用该模块实现Excel数据的写入,感兴趣的小伙伴可以了解一下

  9. 五分钟理解keep alive用法及原理

    这篇文章主要为大家介绍了keep alive用法及原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. JavaScript数据扁平化详解

    这篇文章主要为大家介绍了JavaScript数据扁平化,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部