代码详解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学习基础知识小结
Nov 25 Javascript
教您去掉ie网页加载进度条的方法
Dec 09 Javascript
23个Javascript弹出窗口特效整理
Feb 25 Javascript
JavaScript中的关联数组问题
Mar 04 Javascript
jQuery结合CSS制作漂亮的select下拉菜单
May 03 Javascript
javascript实现动态表头及表列的展现方法
Jul 14 Javascript
jQuery实现的背景动态变化导航菜单效果
Aug 24 Javascript
JS实现在文本指定位置插入内容的简单示例
Dec 22 Javascript
vue实现前进刷新后退不刷新效果
Jan 26 Javascript
Vue双向绑定实现原理与方法详解
May 07 Javascript
vue2.0 watch里面的 deep和immediate用法说明
Oct 30 Javascript
javascript实现时钟动画
Dec 03 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中执行系统外部命令
2006/10/09 PHP
PHP 类商品秒杀计时实现代码
2010/05/05 PHP
php xml 入门学习资料
2011/01/01 PHP
php设置页面超时时间解决方法
2015/09/22 PHP
Laravel多用户认证系统示例详解
2018/03/13 PHP
jQuery 学习第六课 实现一个Ajax的TreeView
2010/05/17 Javascript
jQuery中的height innerHeight outerHeight区别示例介绍
2014/06/15 Javascript
jquery实现类似EasyUI的页面布局可改变左右的宽度
2020/09/12 Javascript
基于javascript的COOkie的操作实现只能点一次
2014/12/26 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
基于jQuery的网页影音播放器jPlayer的基本使用教程
2016/03/08 Javascript
基于jQuery实现的设置文本区域的光标位置
2018/06/15 jQuery
vue实现多个元素或多个组件之间动画效果
2018/09/25 Javascript
使用webpack搭建vue项目及注意事项
2019/06/10 Javascript
Java及python正则表达式详解
2017/12/27 Python
在CentOS6上安装Python2.7的解决方法
2018/01/09 Python
pygame游戏之旅 创建游戏窗口界面
2018/11/20 Python
python中的数据结构比较
2019/05/13 Python
python保存字典和读取字典的实例代码
2019/07/07 Python
Django 模型类(models.py)的定义详解
2019/07/19 Python
Python3 解决读取中文文件txt编码的问题
2019/12/20 Python
python Gabor滤波器讲解
2020/10/26 Python
使用phonegap检测网络状态的方法
2017/03/30 HTML / CSS
Html5 web本地存储实例详解
2016/07/28 HTML / CSS
鞋子女王塔玛拉·梅隆同名奢侈品牌:Tamara Mellon
2017/11/22 全球购物
硅酸盐工业控制专业应届生求职信
2013/11/02 职场文书
《生命的药方》教学反思
2014/04/08 职场文书
英语演讲稿3分钟
2014/04/29 职场文书
会计学专业求职信
2014/07/17 职场文书
2014幼儿园中班工作总结
2014/11/10 职场文书
节约用电倡议书
2015/04/28 职场文书
写给老师的保证书
2015/05/09 职场文书
成绩单家长意见
2015/06/03 职场文书
2019个人工作自我评价范文(3篇)
2019/09/19 职场文书
如何用python插入独创性声明
2021/03/31 Python
世界无敌的ICOM IC-R9500宽频接收机
2022/03/25 无线电