代码详解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 相关文章推荐
JS中动态添加事件(绑定事件)的代码
Jan 09 Javascript
JavaScript学习笔记之JS对象
Jan 22 Javascript
js实现将选中值累加到文本框的方法
Aug 12 Javascript
js识别uc浏览器的代码
Nov 06 Javascript
详解vue项目构建与实战
Jun 27 Javascript
Vue 换肤的示例实践
Jan 23 Javascript
JavaScript反射与依赖注入实例详解
May 29 Javascript
浅谈对于react-thunk中间件的简单理解
May 01 Javascript
vue基本使用--refs获取组件或元素的实例
Nov 07 Javascript
如何在postman测试用例中实现断言过程解析
Jul 09 Javascript
Ajax获取node服务器数据的完整步骤
Sep 20 Javascript
Vue组件化(ref,props, mixin,.插件)详解
May 15 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 无限级缓存的类的扩展
2009/03/16 PHP
PHP伪造来源HTTP_REFERER的方法实例详解
2015/07/06 PHP
PHP版本的选择5.2.17 5.3.27 5.3.28 5.4 5.5兼容性问题分析
2016/04/04 PHP
PHP实现路由映射到指定控制器
2016/08/13 PHP
jquery JSON的解析方式
2009/07/25 Javascript
Javascript new关键字的玄机 以及其它
2010/08/25 Javascript
javascript日期转换 时间戳转日期格式
2011/11/05 Javascript
关于jquery的多个选择器的使用示例
2013/10/18 Javascript
jQuery实现鼠标经过图片预览大图效果
2014/04/10 Javascript
js获取IP地址的方法小结
2014/07/01 Javascript
jQuery源码解读之removeClass()方法分析
2015/02/20 Javascript
JS实现点击复选框将按钮或文本框变为灰色不可用的方法
2015/08/11 Javascript
js鼠标点击图片切换效果代码分享
2015/08/26 Javascript
Angular限制input框输入金额(是小数的话只保留两位小数点)
2017/07/13 Javascript
浅谈React和Redux的连接react-redux
2017/12/04 Javascript
nodejs爬虫初试superagent和cheerio
2018/03/05 NodeJs
Vue + better-scroll 实现移动端字母索引导航功能
2018/05/07 Javascript
layui递归实现动态左侧菜单
2019/07/26 Javascript
[00:09]DOTA2新版本PA至宝特效动作展示
2014/11/19 DOTA
python 简易计算器程序,代码就几行
2009/08/29 Python
Python统计日志中每个IP出现次数的方法
2015/07/06 Python
解决Pycharm中import时无法识别自己写的程序方法
2018/05/18 Python
python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法
2018/09/13 Python
关于Python核心框架tornado的异步协程的2种方法详解
2019/08/28 Python
Python实现自定义读写分离代码实例
2019/11/16 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
2020/03/02 Python
美国传奇滑手Paul Rodriguez创办的街头滑板品牌:Primitive Skateboarding
2019/10/29 全球购物
.net软件工程师面试题
2015/03/31 面试题
教师实习自我鉴定
2013/12/13 职场文书
英文求职信写作小建议
2014/02/16 职场文书
化学教育专业自荐信
2014/07/04 职场文书
学校领导四风问题整改措施思想汇报
2014/10/09 职场文书
2015应届毕业生求职信范文
2015/03/20 职场文书
2015年爱牙日活动总结
2015/03/23 职场文书
pytorch 实现变分自动编码器的操作
2021/05/24 Python
Python使用华为API为图像设置多个锚点标签
2022/04/12 Python