代码详解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 通用简单的table选项卡实现
May 07 Javascript
jQuery UI Dialog 创建友好的弹出对话框实现代码
Apr 12 Javascript
JavaScript之IE的fireEvent方法详细解析
Nov 20 Javascript
JavaScript实现继承的4种方法总结
Oct 16 Javascript
less简单入门(CSS 预处理语言)
Mar 08 Javascript
ionic实现下拉刷新载入数据功能
May 11 Javascript
javascript计算对象长度的方法
Oct 25 Javascript
JS简单实现点击跳转登陆邮箱功能的方法
Oct 31 Javascript
旺旺在线客服代码 旺旺客服代码生成器
Jan 09 Javascript
详解JS转换数值函数Number()、parseInt()、parseFloat()
Aug 24 Javascript
微信小程序显示倒计时功能示例【测试可用】
Dec 03 Javascript
小程序使用分包的示例代码
Mar 23 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
给海燕B411配件机起死回生配上件
2021/03/02 无线电
在同一窗体中使用PHP来处理多个提交任务
2006/10/09 PHP
THINKPHP+JS实现缩放图片式截图的实现
2010/03/07 PHP
利用ThinkPHP内置的ThinkAjax实现异步传输技术的实现方法
2011/12/19 PHP
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
php静态文件返回304技巧分享
2015/01/06 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
Laravel中如何增加自定义全局函数详解
2017/05/09 PHP
Prototype Date对象 学习
2009/07/12 Javascript
修改js Calendar日历控件 兼容IE9/谷歌/火狐
2013/01/04 Javascript
jQuery筛选器children()案例详解(图文)
2013/02/17 Javascript
使用jQuery UI的tooltip函数修饰title属性的气泡悬浮框
2013/06/24 Javascript
浏览器窗口加载和大小改变事件示例
2014/02/27 Javascript
js中的cookie的读写操作示例详解
2014/04/17 Javascript
搭建pomelo 开发环境
2014/06/24 Javascript
javascript实现在线客服效果
2015/07/15 Javascript
JS实现的简洁二级导航菜单雏形效果
2015/10/13 Javascript
Bootstrap编写一个兼容主流浏览器的受众门户式风格页面
2016/07/01 Javascript
js实现tab切换效果
2017/02/16 Javascript
使用jQuery的load方法设计动态加载及解决被加载页面js失效问题
2017/03/01 Javascript
解决eclipse中没有js代码提示的问题
2018/10/10 Javascript
js实现多图和单图上传显示
2019/12/18 Javascript
JS实现盒子拖拽效果
2020/02/06 Javascript
Python使用Flask框架获取当前查询参数的方法
2015/03/21 Python
Python中使用摄像头实现简单的延时摄影技术
2015/03/27 Python
详细解析Python中的变量的数据类型
2015/05/13 Python
python实现提取百度搜索结果的方法
2015/05/19 Python
Python获取当前页面内所有链接的四种方法对比分析
2017/08/19 Python
详解关于Django中ORM数据库迁移的配置
2018/10/08 Python
详解Python 实现 ZeroMQ 的三种基本工作模式
2020/03/24 Python
python 6种方法实现单例模式
2020/12/15 Python
css3学习心得分享
2013/08/19 HTML / CSS
绘儿乐产品官方在线商店:Crayola.com
2019/09/07 全球购物
在校大学生个人的自我评价
2014/02/13 职场文书
化妆师职业生涯规划书
2014/02/16 职场文书
校本教研活动总结
2014/07/01 职场文书