代码详解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对象弹出一个层
Mar 26 Javascript
JavaScript的public、private和privileged模式
Dec 28 Javascript
js parseInt(&quot;08&quot;)未指定进位制问题
Jun 19 Javascript
jquery表格内容筛选实现思路及代码
Apr 16 Javascript
js截取固定长度的中英文字符的简单实例
Nov 22 Javascript
node.js中的socket.io入门实例
Apr 26 Javascript
JS+CSS实现仿触屏手机拨号盘界面及功能模拟完整实例
May 16 Javascript
JS或jQuery获取ASP.NET服务器控件ID的方法
Jun 08 Javascript
javascript拖拽应用实例
Mar 25 Javascript
轻松理解JavaScript闭包
Mar 14 Javascript
小程序实现选择题选择效果
Nov 04 Javascript
vue.js 2.0实现简单分页效果
Jul 29 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面向对象分析设计的61条军规小结
2010/07/17 PHP
PHP的变量类型和作用域详解
2014/03/12 PHP
php自定义错误处理用法实例
2015/03/20 PHP
详解PHP+AJAX无刷新分页实现方法
2015/11/03 PHP
Yii2实现同时搜索多个字段的方法
2016/08/10 PHP
动态表单验证的操作方法和TP框架里面的ajax表单验证
2017/07/19 PHP
jquery实现居中弹出层代码
2010/08/25 Javascript
showModalDialog模态对话框的使用详解以及浏览器兼容
2014/01/11 Javascript
在JavaScript中模拟类(class)及类的继承关系
2016/05/20 Javascript
jquery判断对象是否为空并遍历对象的简单实例
2016/07/26 Javascript
angularjs路由传值$routeParams详解
2020/09/05 Javascript
jquery ajaxfileuplod 上传文件 essyui laoding 效果【防止重复上传文件】
2018/05/26 jQuery
看看“疫苗查询”小程序有温度的代码
2018/07/31 Javascript
微信小程序实现简单跑马灯效果
2020/05/26 Javascript
微信小程序保存多张图片的实现方法
2019/03/05 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
2019/08/23 Javascript
微信小程序左滑删除实现代码实例
2019/09/16 Javascript
[52:02]完美世界DOTA2联赛PWL S2 FTD.C vs SZ 第一场 11.27
2020/11/30 DOTA
跟老齐学Python之编写类之四再论继承
2014/10/11 Python
python并发编程之线程实例解析
2017/12/27 Python
python爬虫获取多页天涯帖子
2018/02/23 Python
python批量获取html内body内容的实例
2019/01/02 Python
Python实现对adb命令封装
2020/03/06 Python
python调用私有属性的方法总结
2020/07/24 Python
灵活运用CSS3特性绘制简易版围棋效果
2016/09/28 HTML / CSS
中国高端家电购物商城:顺电
2018/03/04 全球购物
俄罗斯香水和化妆品网上商店:NOTINO.ru
2019/12/17 全球购物
super()与this()的区别
2016/01/17 面试题
土木工程专业个人求职信
2013/12/05 职场文书
四年大学生活的个人自我评价
2013/12/11 职场文书
新闻编辑专业毕业自荐书范文
2014/02/05 职场文书
工作岗位说明书模板
2014/05/09 职场文书
教师党员先进性教育自我剖析材料思想汇报
2014/09/24 职场文书
自主招生学校推荐信
2014/09/26 职场文书
2014年信息宣传工作总结
2014/12/18 职场文书
Go语言怎么使用变长参数函数
2022/07/15 Golang