代码详解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实现的map方法示例代码
Jan 13 Javascript
Node.js 异步编程之 Callback介绍(一)
Mar 30 Javascript
Bootstrap table分页问题汇总
May 30 Javascript
JavaScript实现点击按钮复制指定区域文本(推荐)
Nov 25 Javascript
JS实现重新加载当前页面
Nov 29 Javascript
jQuery排序插件tableSorter使用方法
Feb 10 Javascript
深入研究React中setState源码
Nov 17 Javascript
利用vue + element实现表格分页和前端搜索的方法
Dec 25 Javascript
vue组件name的作用小结
May 23 Javascript
使用pkg打包Node.js应用的方法步骤
Oct 19 Javascript
小程序组件之自定义顶部导航实例
Jun 12 Javascript
koa中间件核心(koa-compose)源码解读分析
Jun 15 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 zlib压缩和解压缩swf文件的代码
2008/12/30 PHP
PHP实现无限极分类图文教程
2014/11/25 PHP
PHP封装的验证码工具类定义与用法示例
2018/08/22 PHP
Jquery Autocomplete 结合asp.net使用要点
2010/10/29 Javascript
jquery表单验证使用插件formValidator
2012/11/10 Javascript
jquery垂直公告滚动实现代码
2013/12/08 Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
2014/04/15 Javascript
jQuery中:visible选择器用法实例
2014/12/30 Javascript
js实现点击链接后延迟3秒再跳转的方法
2015/06/05 Javascript
javascript检测flash插件是否被禁用的方法
2016/01/14 Javascript
给angular加上动画效遇到的问题总结
2016/02/17 Javascript
jQuery获取访问者IP地址的方法(基于新浪API与QQ查询接口)
2016/05/25 Javascript
Jquery基础之事件操作详解
2016/06/14 Javascript
JS作为值的函数用法示例
2016/06/20 Javascript
微信小程序 wx.request(接口调用方式)详解及实例
2016/11/23 Javascript
详解jQuery选择器
2016/12/21 Javascript
react-native封装插件swiper的使用方法
2018/03/20 Javascript
Vue 让元素抖动/摆动起来的实现代码
2018/05/31 Javascript
原生JS实现的简单小钟表功能示例
2018/08/30 Javascript
[01:25:09]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS DT第二场
2014/05/24 DOTA
Python中使用语句导入模块或包的机制研究
2015/03/30 Python
Python多线程编程(五):死锁的形成
2015/04/05 Python
python创建进程fork用法
2015/06/04 Python
浅谈Python中chr、unichr、ord字符函数之间的对比
2016/06/16 Python
基于anaconda下强大的conda命令介绍
2018/06/11 Python
Django rest framework jwt的使用方法详解
2019/08/08 Python
Python网页解析器使用实例详解
2020/05/30 Python
python re.match()用法相关示例
2021/01/27 Python
Python面试题:如何用Python来发送邮件
2016/03/15 面试题
办公室副主任岗位职责
2013/11/25 职场文书
明星邀请函
2015/02/02 职场文书
聚众斗殴罪辩护词
2015/05/21 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
2016党员干部廉洁自律心得体会
2016/01/13 职场文书
筑梦中国心得体会
2016/01/18 职场文书
SQL基础的查询语句
2021/11/11 MySQL