代码详解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启动应用程序的一个简单例子
May 11 Javascript
Js 订制自己的AlertBox(信息提示框)
Jan 09 Javascript
js获取鼠标点击的位置实现思路及代码
May 09 Javascript
JavaScript中的Primitive对象封装介绍
Dec 31 Javascript
超实用的JavaScript表单代码段
Feb 26 Javascript
Node.js服务器环境下使用Mock.js拦截AJAX请求的教程
May 23 Javascript
js 获取经纬度的实现方法
Jun 20 Javascript
lhgcalendar时间插件限制只能选择三个月的实现方法
Jul 03 Javascript
JS判断微信扫码的方法
Aug 07 Javascript
产制造追溯系统之通过微信小程序实现移动端报表平台
Jun 03 Javascript
深入解读Node.js中的koa源码
Jun 17 Javascript
使用flow来规范javascript的变量类型
Sep 12 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+Ajax异步通讯实现用户名邮箱验证是否已注册( 2种方法实现)
2011/12/28 PHP
php eval函数用法总结
2012/10/31 PHP
PHP进阶学习之垃圾回收机制详解
2019/06/18 PHP
php redis setnx分布式锁简单原理解析
2020/10/23 PHP
收集的网上用的ajax之chat.js文件
2007/04/08 Javascript
转一个日期输入控件,支持FF
2007/04/27 Javascript
简体中文转换繁体中文(实现代码)
2013/12/25 Javascript
ie8模式下click无反应点击option无反应的解决方法
2014/10/11 Javascript
Javascript基础教程之数据类型 (数值 Number)
2015/01/18 Javascript
jQuery中$.click()无效问题分析
2015/01/29 Javascript
javascript实现淡蓝色的鼠标拖动选择框实例
2015/05/09 Javascript
深入理解Javascript中的valueOf与toString
2017/01/04 Javascript
jQuery animate()实现背景色渐变效果的处理方法【使用jQuery.color.js插件】
2017/03/15 Javascript
jQuery查找dom的几种方法效率详解
2017/05/17 jQuery
Vue.js结合Ueditor富文本编辑器的实例代码
2017/07/11 Javascript
详解刷新页面vuex数据不消失和不跳转页面的解决
2018/01/30 Javascript
详解Angular6.0使用路由步骤(共7步)
2018/06/29 Javascript
vue中tab选项卡的实现思路
2018/11/25 Javascript
Layui动态生成select下拉选择框不显示的解决方法
2019/09/24 Javascript
html2canvas属性和使用方法以及如何使用html2canvas将HTML内容写入Canvas生成图片
2020/01/12 Javascript
创建nuxt.js项目流程图解
2020/03/13 Javascript
ant-design-vue按需加载的坑的解决
2020/05/14 Javascript
Windows和Linux下使用Python访问SqlServer的方法介绍
2015/03/10 Python
Python字典数据对象拆分的简单实现方法
2017/12/05 Python
详解Python自建logging模块
2018/01/29 Python
Django使用unittest模块进行单元测试过程解析
2019/08/02 Python
使用npy转image图像并保存的实例
2020/07/01 Python
python json.dumps() json.dump()的区别详解
2020/07/14 Python
BOSE德国官网:尽探索之力,享音乐之极
2016/12/11 全球购物
中科创达面试题
2016/12/28 面试题
环境工程大学生个人的自我评价
2013/10/08 职场文书
委托书的格式
2014/08/01 职场文书
几款流行的HTML5 UI框架比较(小结)
2021/04/08 HTML / CSS
解析laravel使用workerman用户交互、服务器交互
2021/04/28 PHP
Spring Bean的实例化之属性注入源码剖析过程
2021/06/13 Java/Android
浅谈MySQL 亿级数据分页的优化
2021/06/15 MySQL