代码详解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 相关文章推荐
基于JQuery的一句代码实现表格的简单筛选
Jul 26 Javascript
jquery+ajax每秒向后台发送请求数据然后返回页面的代码
Jan 17 Javascript
多种方法实现JS动态添加事件
Nov 01 Javascript
jquery实现全屏滚动
Dec 28 Javascript
表单元素值获取方式js及java方式的简单实例
Oct 15 Javascript
使用Node.js搭建静态资源服务详细教程
Aug 02 Javascript
vue组件编写之todolist组件实例详解
Jan 22 Javascript
原生JS实现的双色球功能示例
Feb 02 Javascript
vue init webpack 建vue项目报错的解决方法
Sep 29 Javascript
详解VS Code使用之Vue工程配置format代码格式化
Mar 20 Javascript
vue发送websocket请求和http post请求的实例代码
Jul 11 Javascript
TensorFlow.js 微信小程序插件开始支持模型缓存的方法
Feb 21 Javascript
详解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自定义apk安装包实例
2014/10/20 PHP
Yii框架组件和事件行为管理详解
2016/05/20 PHP
跟随鼠标旋转的文字
2006/11/30 Javascript
监控 url fragment变化的js代码
2010/04/19 Javascript
jquery 插件学习(一)
2012/08/06 Javascript
JavaScript获取FCK编辑器信息的具体方法
2013/07/12 Javascript
使用jQuery实现的掷色子游戏动画效果
2014/03/14 Javascript
Javascript限制网页只能在微信内置浏览器中访问
2014/11/09 Javascript
nodejs实现的一个简单聊天室功能分享
2014/12/06 NodeJs
JS+CSS实现可拖拽的漂亮圆角特效弹出层完整实例
2015/02/13 Javascript
JQuery中attr方法和removeAttr方法用法实例
2015/05/18 Javascript
js操作XML文件的实现方法兼容IE与FireFox
2016/06/25 Javascript
微信小程序 获取相册照片实例详解
2016/11/16 Javascript
解析微信JS-SDK配置授权,实现分享接口
2016/12/09 Javascript
vue观察模式浅析
2018/09/25 Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
2019/01/09 Javascript
微信小程序 scroll-view 水平滚动实现过程解析
2019/10/12 Javascript
vue v-for 点击当前行,获取当前行数据及event当前事件对象的操作
2020/09/10 Javascript
[43:43]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第三场 11.29
2020/12/02 DOTA
Python图像处理之简单画板实现方法示例
2018/08/30 Python
Python使用sqlalchemy模块连接数据库操作示例
2019/03/13 Python
解决Djang2.0.1中的reverse导入失败的问题
2019/08/16 Python
python中dict()的高级用法实现
2019/11/13 Python
简单了解Python3 bytes和str类型的区别和联系
2019/12/19 Python
浅谈python出错时traceback的解读
2020/07/15 Python
详解pandas赋值失败问题解决
2020/11/29 Python
安装不同版本的tensorflow与models方法实现
2021/02/20 Python
CSS3之2D与3D变换的实现方法
2019/01/28 HTML / CSS
法国床上用品商店:La Compagnie du lit
2019/12/26 全球购物
与C++相比,Java中的数组有什么不同
2014/03/25 面试题
自动化毕业生专业自荐书范文
2014/02/04 职场文书
《厄运打不垮的信念》教学反思
2014/04/13 职场文书
电影建党伟业观后感
2015/06/01 职场文书
python 解决微分方程的操作(数值解法)
2021/05/26 Python
CSS 实现Chrome标签栏的技巧
2021/08/04 HTML / CSS
MySQL分区以及建索引的方法总结
2022/04/13 MySQL