代码详解Vuejs响应式原理


Posted in Javascript onDecember 20, 2017

响应式原理

> vuejs中的模型(model)和视图(view)是保持同步的,在修改数据的时候会自动更新视图,这其实依赖于Object.defineProperty方法,所以vuejs不支持IE8及以下版本,vuejs通过劫持getter/setter方法来监听数据的变化,通过getter进行依赖收集,在数据变更执行setter的时候通知视图更新。

Object.defineProperty

> Object.defineProperty可以定义对象的属性或修改对象的属性
> 目前可以通过 Object.defineProperty描述的属性分为两种:数据属性和访问器属性

// obj: 对象
// prop: 对象中的属性
// descriptor: 对象中的属性的特性
Object.defineProperty(obj,prop,descriptor);

数据属性 > 数据属性的descriptor包含四种:value、writable、enumerable、configurable

var person = {
  name: 'json',
  age: 18
}

Object.defineProperty(person, 'name', {
  value: 'John',     // 属性的值,默认为undefined
  writable: false,    // 是否可以重写属性的值,设为false便是只读的
  enumerable: false,   // 是否可枚举(for in或Object.keys),默认为false
  configurable: true   // 是否可以删除或者重新设定上述配置,默认为false
})

person.name = 'new name';
console.log(person.name); // 'John'

for(key in person) console.log(person[key]);  // 18

Object.defineProperty(person, 'name', {
  writable: true,    
  enumerable: true,   
  configurable: false   
})

person.name = 'new name';
console.log(person.name); // 'new name'

for(key in person) console.log(person[key]);  // 'new name',18

访问器属性 > 访问器属性的desciptor包含四种:get、set、enumerable、configurable

var person = { _age: 20 };

Object.defineProperty(person, 'age',{
  get: function(){
    return this._age;
  },
  set: function(age){
    this._age = age < 0 ? 0 : age;
  }
});

person.age = 5;   // _age == 5
person.age = -3;  // _age == 0
person._age = -3;  // _age == -3

Vuejs劫持数据的做法

function observer(value, cb) {
  // 遍历对象的所有属性并为对象添加对应的访问器属性
  Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}
function defineReactive (obj, key, val, cb) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: ()=>{
      /*....依赖收集等....*/
    },
    set:newVal=> {
      cb();/*订阅者收到消息的回调,这里为render函数,即重新渲染*/
    }
  })
}
class Vue {
  constructor(options) {
    this._data = options.data;
    observer(this._data, options.render)  /*把所有数据变成可观察的*/
  }
}
let app = new Vue({
  el: '#app',
  data: {
    text: 'text',
    text2: 'text2'
  },
  render(){
    console.log("render");
  }
})

残留问题 > 上述实现只有通过app._data_text才会触发set,那么怎样才能做到app.text就能触发set呢
代理

> 通过在this对象中添加访问器属性即可实现代理,然后就可以用app.text来代替app._data.text了

_proxy(options.data);/*构造函数中*/

/*代理*/
function _proxy (data) {
  const that = this;
  Object.keys(data).forEach(key => {
    Object.defineProperty(that, key, {
      configurable: true,
      enumerable: true,
      get: function proxyGetter () {
        return that._data[key];
      },
      set: function proxySetter (val) {
        that._data[key] = val;
      }
    })
  });
}

以上就是本次文章的全部内容,大家如果还有任何不明白的地方可以在下方的留言区讨论。

Javascript 相关文章推荐
Javascript 面向对象 重载
May 13 Javascript
jquery 学习之一 对象访问
Nov 23 Javascript
Jquery封装tab自动切换效果的具体实现
Jul 13 Javascript
jquery validation验证身份证号,护照,电话号码,email(实例代码)
Nov 06 Javascript
jquery广告无缝轮播实例
Jan 05 Javascript
微信小程序使用checkbox显示多项选择框功能【附源码下载】
Dec 11 Javascript
require.js 加载过程与使用方法介绍
Oct 30 Javascript
微信小程序实现展示评分结果功能
Feb 15 Javascript
详解Vue-cli3 项目在安卓低版本系统和IE上白屏问题解决
Apr 14 Javascript
小程序数据通信方法大全(推荐)
Apr 15 Javascript
JavaScript实现页面动态验证码的实现示例
Mar 23 Javascript
vue实现Toast组件轻提示
Apr 10 Vue.js
详解Javascript 中的 class、构造函数、工厂函数
Dec 20 #Javascript
在一个页面实现两个zTree联动的方法
Dec 20 #Javascript
浅谈基于Vue.js的移动组件库cube-ui
Dec 20 #Javascript
Angular2+如何去除url中的#号详解
Dec 20 #Javascript
JS基于递归实现网页版计算器的方法分析
Dec 20 #Javascript
JS小球抛物线轨迹运动的两种实现方法详解
Dec 20 #Javascript
JavaScript实现二叉树定义、遍历及查找的方法详解
Dec 20 #Javascript
You might like
php session_start()出错原因分析及解决方法
2013/10/28 PHP
ThinkPHP查询返回简单字段数组的方法
2014/08/25 PHP
PHP数组排序之sort、asort与ksort用法实例
2014/09/08 PHP
phpQuery让php处理html代码像jQuery一样方便
2015/01/06 PHP
PHP数组去重比较快的实现方式
2016/01/19 PHP
基于jQuery+HttpHandler实现图片裁剪效果代码(适用于论坛, SNS)
2011/09/02 Javascript
本地图片预览(支持IE6/IE7/IE8/Firefox3)经验总结
2013/03/25 Javascript
jquery数组过滤筛选方法grep()简介
2014/06/06 Javascript
Flexigrid在IE下不显示数据的有效处理方法
2014/09/04 Javascript
bootstrap——bootstrapTable实现隐藏列的示例
2017/01/14 Javascript
javascript 组合按键事件监听实现代码
2017/02/21 Javascript
AngularJS集合数据遍历显示的实例
2017/12/27 Javascript
webpack下实现动态引入文件方法
2018/02/22 Javascript
jQuery实现基本动画效果的方法详解
2018/09/06 jQuery
微信实现自动跳转到用其他浏览器打开指定APP下载
2019/02/15 Javascript
实现高性能javascript的注意事项
2019/05/27 Javascript
Vue的Options用法说明
2020/08/14 Javascript
[07:25]DOTA2-DPC中国联赛2月5日Recap集锦
2021/03/11 DOTA
Python连接MySQL并使用fetchall()方法过滤特殊字符
2016/03/13 Python
python中解析json格式文件的方法示例
2017/05/03 Python
python中MethodType方法介绍与使用示例
2017/08/03 Python
想学python 这5本书籍你必看!
2018/12/11 Python
Python for循环与range函数的使用详解
2019/03/23 Python
python的time模块和datetime模块实例解析
2019/11/29 Python
python 实现批量替换文本中的某部分内容
2019/12/13 Python
python实现ftp文件传输系统(案例分析)
2020/03/20 Python
英国莱斯特松木橡木家具网上商店:Choice Furniture Superstore
2019/07/05 全球购物
Currentbody法国:健康与美容高科技产品
2020/08/16 全球购物
会计师事务所审计实习自我鉴定
2013/09/20 职场文书
主持人演讲稿范文
2013/12/28 职场文书
致全体运动员广播稿
2014/02/01 职场文书
幼儿园班级工作总结2015
2015/05/25 职场文书
2016年教师节慰问信
2015/12/01 职场文书
初中美术教学反思
2016/02/17 职场文书
管理者日常工作必备:22条企业管理流程模板!
2019/07/12 职场文书
JS异步堆栈追踪之为什么await胜过Promise
2021/04/28 Javascript