代码详解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简单的轮播的图片滚动实例
Jun 17 Javascript
js 图片随机不定向浮动的实现代码
Jul 02 Javascript
使用javascript提交form表单方法汇总
Jun 25 Javascript
JavaScript编写点击查看大图的页面半透明遮罩层效果实例
May 09 Javascript
JS实现根据文件字节数返回文件大小的方法
Aug 02 Javascript
bootstrap fileinput 上传插件的基础使用
Feb 17 Javascript
JavaScript实现替换字符串中最后一个字符的方法
Mar 07 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
Jul 27 Javascript
微信小程序简单实现form表单获取输入数据功能示例
Nov 30 Javascript
Vue+mui实现图片的本地缓存示例代码
May 24 Javascript
Javascript读写cookie的实例源码
Mar 16 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
Apr 11 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 模拟get_headers函数的代码示例
2013/04/27 PHP
通过table标签,PHP输出EXCEL的实现方法
2013/07/24 PHP
PHP中使用Session配合Javascript实现文件上传进度条功能
2014/10/15 PHP
web性能优化之javascript性能调优
2012/12/28 Javascript
jquery验证表单中的单选与多选实例
2013/08/18 Javascript
文本框回车提交与禁止提交示例
2013/09/27 Javascript
JavaScript编程中布尔对象的基本使用
2015/10/25 Javascript
React实现点击删除列表中对应项
2017/01/10 Javascript
详解Node.js实现301、302重定向服务
2017/04/07 Javascript
深入解析nodejs HTTP服务
2017/07/25 NodeJs
快速解决select2在bootstrap模态框中下拉框隐藏的问题
2018/08/10 Javascript
vue - props 声明数组和对象操作
2020/07/30 Javascript
[00:58]PWL开团时刻DAY5——十人开雾0换5
2020/11/04 DOTA
Python中super()函数简介及用法分享
2016/07/11 Python
使用Python &amp; Flask 实现RESTful Web API的实例
2017/09/19 Python
python中logging包的使用总结
2018/02/28 Python
Python Selenium 之关闭窗口close与quit的方法
2019/02/13 Python
python买卖股票的最佳时机(基于贪心/蛮力算法)
2019/07/05 Python
Python学习笔记之集合的概念和简单使用示例
2019/08/22 Python
解决django后台管理界面添加中文内容乱码问题
2019/11/15 Python
python中使用input()函数获取用户输入值方式
2020/05/03 Python
使用Keras实现Tensor的相乘和相加代码
2020/06/18 Python
为什么python比较流行
2020/06/19 Python
Python根据指定文件生成XML的方法
2020/06/29 Python
python 如何用urllib与服务端交互(发送和接收数据)
2021/03/04 Python
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
详解CSS中iconfont的使用
2015/08/04 HTML / CSS
SKECHERS官方旗舰店:美国舒适运动休闲品牌
2017/12/22 全球购物
食堂员工工作职责
2013/12/18 职场文书
高中打架检讨书
2014/02/13 职场文书
村抢险救灾方案
2014/05/09 职场文书
工人先锋号事迹材料
2014/12/24 职场文书
2015年语文教师工作总结
2015/05/25 职场文书
导游词之新疆-喀纳斯
2019/10/10 职场文书
CSS3新特性详解(五):多列columns column-count和flex布局
2021/04/30 HTML / CSS
PO模式在selenium自动化测试框架的优势
2022/03/20 Python