代码详解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基于jQuery的表格悬停变色/恢复,表格点击变色/恢复,点击行选Checkbox
Aug 05 Javascript
基于JavaScript实现复选框的全选和取消全选
Feb 09 Javascript
js 索引下标之li集合绑定点击事件
Jan 12 Javascript
解决vue打包css文件中背景图片的路径问题
Sep 03 Javascript
基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
May 07 Javascript
小程序登录/注册页面设计的实现代码
May 24 Javascript
利用原生JS实现data方法示例代码
May 28 Javascript
如何使用CSS3和JQuery easing 插件制作绚丽菜单
Jun 18 jQuery
微信小程序获取复选框全选反选选中的值(实例代码)
Dec 17 Javascript
vue项目使用高德地图的定位及关键字搜索功能的实例代码(踩坑经验)
Mar 07 Javascript
JSON获取属性值方法代码实例
Jun 30 Javascript
【js设计模式】SOLID五大设计原则
Mar 24 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
JSON 和 JavaScript eval使用说明
2010/06/13 Javascript
JS 跳转页面延迟2种方法
2013/03/29 Javascript
禁止ajax缓存获取程序最新数据的方法
2013/11/19 Javascript
jquery 按键盘上的enter事件
2014/05/11 Javascript
javascript时间函数大全
2014/06/30 Javascript
javascript里绝对用的上的字符分割函数总结
2014/07/31 Javascript
javascript trim函数在IE下不能用的解决方法
2014/09/12 Javascript
Node.js中的模块机制学习笔记
2014/11/04 Javascript
触屏中的JavaScript事件分析
2015/02/06 Javascript
js实现浏览本地文件并显示扩展名的方法
2015/08/17 Javascript
使用vue.js编写蓝色拼图小游戏
2017/03/17 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
详解Angular操作cookies方法
2018/06/01 Javascript
基于JS实现简单滑块拼图游戏
2019/10/12 Javascript
关于vue属性使用和不使用冒号的区别说明
2020/10/22 Javascript
带你了解python装饰器
2017/06/15 Python
我们为什么要减少Python中循环的使用
2019/07/10 Python
windows上彻底删除jupyter notebook的实现
2020/04/13 Python
Python使用socket_TCP实现小文件下载功能
2020/10/09 Python
python 实现非极大值抑制算法(Non-maximum suppression, NMS)
2020/10/15 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
世界上最大的二手相机店:KEN
2017/05/17 全球购物
美国特价机票专家:Airfarewatchdog
2018/01/24 全球购物
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
办公室主任岗位职责
2013/11/08 职场文书
工程部经理岗位职责
2013/12/08 职场文书
编辑找工作求职信范文
2013/12/16 职场文书
写给老婆的检讨书
2014/02/21 职场文书
环保倡议书格式范文
2014/05/14 职场文书
党员干部民主生活会议批评与自我批评材料
2014/09/20 职场文书
2014年教研工作总结
2014/12/06 职场文书
会计工作态度自我评价
2015/03/06 职场文书
新郎父母婚礼答谢词
2015/09/29 职场文书
2016年社会主义核心价值观心得体会
2016/01/21 职场文书
社会心理学学习心得体会
2016/01/22 职场文书
一文搞懂Python Sklearn库使用
2021/08/23 Python