代码详解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 相关文章推荐
JQuery 插件制作实践 xMarquee插件V1.0
Apr 02 Javascript
JS维吉尼亚密码算法实现代码
Nov 09 Javascript
js禁止回车提交表单的示例代码
Dec 23 Javascript
js与运算符和或运算符的妙用
Feb 14 Javascript
浅谈 jQuery 事件源码定位问题
Jun 18 Javascript
百度UEditor编辑器如何关闭抓取远程图片功能
Mar 03 Javascript
innerHTML属性,outerHTML属性,textContent属性,innerText属性区别详解
Mar 13 Javascript
js+canvas绘制矩形的方法
Jan 28 Javascript
HTML中setCapture、releaseCapture 使用方法浅析
Sep 25 Javascript
Angular.JS学习之依赖注入$injector详析
Oct 20 Javascript
Webpack 服务器端代码打包的示例代码
Sep 19 Javascript
fullpage.js最后一屏滚动方式
Feb 06 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下防止单引号,双引号在接受页面转义的设置方法
2008/09/25 PHP
php session安全问题分析
2011/06/24 PHP
php设计模式 Facade(外观模式)
2011/06/26 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
Nigma vs Liquid BO3 第二场2.14
2021/03/10 DOTA
Javascript学习笔记7 原型链的原理
2010/01/11 Javascript
基于jquery实现的鼠标滑过按钮改变背景图片
2011/07/15 Javascript
css+js实现部分区域高亮可编辑遮罩层
2014/03/04 Javascript
JavaScript操作Cookie方法实例分析
2015/05/27 Javascript
JavaScript判断对象是否为数组
2015/12/22 Javascript
ajax在兼容模式下失效的快速解决方法
2016/03/22 Javascript
Javascript中的 “&amp;” 和 “|” 详解
2017/02/02 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
JavaScript实现移动端轮播效果
2017/06/06 Javascript
vue-router判断页面未登录自动跳转到登录页的方法示例
2018/11/04 Javascript
小程序分页实践之编写可复用分页组件
2019/07/18 Javascript
微信小程序封装多张图片上传api代码实例
2019/12/30 Javascript
JavaScript canvas动画实现时钟效果
2020/02/10 Javascript
Vue中nprogress页面加载进度条的方法实现
2020/11/13 Javascript
[04:50]DOTA2亚洲邀请赛小组赛第四日 TOP10精彩集锦
2015/02/02 DOTA
python使用自定义user-agent抓取网页的方法
2015/04/15 Python
python制作websocket服务器实例分享
2016/11/20 Python
Python爬虫利用cookie实现模拟登陆实例详解
2017/01/12 Python
python爬取亚马逊书籍信息代码分享
2017/12/09 Python
Python网络编程使用select实现socket全双工异步通信功能示例
2018/04/09 Python
python GUI库图形界面开发之PyQt5信号与槽多窗口数据传递详细使用方法与实例
2020/03/08 Python
使用Django清空数据库并重新生成
2020/04/03 Python
amazeui页面分析之登录页面的示例代码
2020/08/25 HTML / CSS
英国最大的正宗复古足球衫制造商和零售商:TOFFS
2018/06/21 全球购物
美国工业用品采购网站:Zoro.com
2020/10/27 全球购物
《一个小村庄的故事》教学反思
2014/04/13 职场文书
销售顾问工作计划书
2014/08/15 职场文书
预备党员群众路线思想汇报2014
2014/10/25 职场文书
勇敢的心观后感
2015/06/09 职场文书
python实现自定义日志的具体方法
2021/05/28 Python
Python 中面向接口编程
2022/05/20 Python