代码详解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客户端将指定区域导出到Word、Excel的代码
Oct 22 Javascript
jQuery对象和DOM对象的相互转化实现代码
Mar 02 Javascript
JS在TextArea光标位置插入文字并实现移动光标到文字末尾
Jun 21 Javascript
Javascript日期格式化format函数的使用方法
Aug 30 Javascript
微信小程序 支付功能实现PHP实例详解
May 12 Javascript
jquery单击文字或图片内容放大并居中显示
Jun 23 jQuery
简单实现js轮播图效果
Jul 14 Javascript
mui back 返回刷新页面的实例
Dec 06 Javascript
小程序rich-text组件如何改变内部img图片样式的方法
May 22 Javascript
vue-cli3项目升级到vue-cli4 的方法总结
Mar 19 Javascript
vue项目在webpack2实现移动端字体自适配功能
Jun 02 Javascript
纯js+css实现在线时钟
Aug 18 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中的Class的几点个人看法
2006/10/09 PHP
请php正则走开
2008/03/15 PHP
php变量作用域的深入解析
2013/06/03 PHP
解析php中const与define的应用区别
2013/06/18 PHP
php实现的ping端口函数实例
2014/11/12 PHP
php入门教程之Zend Studio设置与开发实例
2016/09/09 PHP
PHPExcel在linux环境下导出报500错误的解决方法
2017/01/26 PHP
PHP多维数组排序array详解
2017/11/21 PHP
PHPCrawl爬虫库实现抓取酷狗歌单的方法示例
2017/12/21 PHP
Laravel框架基础语法与知识点整理【模板变量、输出、include引入子视图等】
2019/12/03 PHP
javascript 模拟点击广告
2010/01/02 Javascript
javascript cookies 设置、读取、删除实例代码
2010/04/12 Javascript
Jquery刷新页面背景图片随机变换的实现方法
2013/03/15 Javascript
jQuery语法高亮插件支持各种程序源代码语法着色加亮
2013/04/27 Javascript
js 本地预览的简单实现方法
2014/02/18 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
2015/12/02 Javascript
javascript实现html页面之间参数传递的四种方法实例分析
2015/12/15 Javascript
详解Bootstrap创建表单的三种格式(一)
2016/01/04 Javascript
原生javascript实现解析XML文档与字符串
2016/03/01 Javascript
springMVC结合AjaxForm上传文件
2016/07/12 Javascript
基于jquery实现多选下拉列表
2017/08/02 jQuery
swiper动态改变滑动内容的实现方法
2018/01/17 Javascript
JS运动特效之任意值添加运动的方法分析
2018/01/24 Javascript
详解React中合并单元格的正确写法
2019/01/08 Javascript
[01:02]2014 DOTA2国际邀请赛中国区预选赛 现场抢先看
2014/05/22 DOTA
深入理解Python对Json的解析
2017/02/14 Python
spark dataframe 将一列展开,把该列所有值都变成新列的方法
2019/01/29 Python
Python趣味入门教程之循环语句while
2020/08/26 Python
用python批量移动文件
2021/01/14 Python
萨克斯第五大道精品百货店: Saks Fifth Avenue
2017/04/28 全球购物
名人珠宝设计师:Melinda Maria Jewelry
2019/03/06 全球购物
BannerBuzz加拿大:在线定制横幅印刷、广告和标志
2020/03/10 全球购物
歌颂祖国演讲稿
2014/05/04 职场文书
学校法制宣传日活动总结
2014/11/01 职场文书
办公用房租赁协议书
2014/11/29 职场文书
2014年稽查工作总结
2014/12/20 职场文书