3分钟了解vue数据劫持的原理实现


Posted in Javascript onMay 01, 2019

目的: 了解Object.defineProperty如何实现数据劫持

大致原理是这样的:

  1. 定义一个监听函数,对对象的每一个属性进行监听
  2. 通过Object.defineProperty对监听的每一个属性设置get 和 set 方法。
  3. 对对象实行监听
  4. 对对象内嵌对象进行处理
  5. 对数组对象进行处理

1. 先定义一个对象

let obj = {
 name: 'jw'
}

2. 定义一个监听函数

/**
* 判断监听的是否是对象
* 如果是对象,就遍历,并且对每个属性进行定义get 和 set
*/

function observer(obj) {
 if(typeof obj === 'object') {
  for (let key in obj) {
  // defineReactive 方法设置get和set,见第三步
   defineReactive(obj, key, obj[key]);
  }
 }
}

3.定义一个函数,处理每个属性

function defineReactive(obj, key, value) {
 Object.defineProperty(obj, key, {
  get() {
   return value;
  },
  set(val) {
   console.log('数据更新了')
   value = val;
  }
 })
}

ok. 到这里初版已经实现了。尝试一下吧

observer(obj);
obj.name = 'haha'

控制台输出:
//数据更新了

以上已经实现设置obj的属性的时候,被监听到,并且可以去执行一些代码了。但是,如果对象里面嵌入了对象呢?比如:

let obj = {
 name: 'jw',
 age: {
  old: 60
 }
}

执行以下代码

observer(obj);
obj.age.old = '50'

控制台输出: 空

4.对监控的obj进行迭代处理

// 修改defineReactive , 添加一行代码
function defineReactive(obj, key, value) {
 // 如果对象的属性也是一个对象。迭代处理
 observer(value);
 Object.defineProperty(obj, key, {
  //....
 })
}

再执行以下代码:

observer(obj);
obj.age.old = '50'

控制台输出:
//数据更新了

可惜的是,如果对象是一个数组,Object.defineProperty就无法起作用了,比如:

obj.skill = [1, 2, 3];
obj.age.push(4);

控制台输出:
//空

实际上,不止push,包括slice,shift,unshif...都是没有作用.

5. 重写数组的方法

let arr = ['push', 'slice', 'shift', 'unshift'];
arr.forEach(method=> {
 let oldPush = Array.prototype[method];
 Array.prototype[method] = function(value) {
  console.log('数据更新了')
  oldPush.call(this, value)
 }
})

再执行以下代码:

obj.skill = [1, 2, 3];
obj.skill.push(4);

控制台输出:
//数据更新了

但是,数组的length操作仍然是无效的。这也是为什么vue中只能通过方法去改变数组的原因了。

总结: Object.defineProperty只是解决了状态变更后,如何触发通知的问题,那要通知谁呢?谁会关心那些属性发生了变化呢?以后再说。

以下完整代码

let obj = {
 name: 'jw',
 age: {
  old: '60'
 }
}

// vue 数据劫持 Observer.defineProperty

function observer(obj) {
 if(typeof obj === 'object') {
  for (let key in obj) {
   defineReactive(obj, key, obj[key]);
  }
 }
}

function defineReactive(obj, key, value) {
 observer(value);

 Object.defineProperty(obj, key, {
  get() {
   return value;
  },
  set(val) {
   console.log('数据更新了')
   value = val;
  }
 })
}
observer(obj);


// obj.age.old = '50'


// Object.defineProperty 对 数组无效
let arr = ['push', 'slice', 'shift', 'unshift'];

arr.forEach(method=> {
 let oldPush = Array.prototype[method];
 Array.prototype[method] = function(value) {
  console.log('数据更新了')
  oldPush.call(this, value)
 }
})
obj.skill = [1, 2, 3];
obj.skill.push(4);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript下申明对象的几种方法小结
Oct 02 Javascript
将CKfinder整合进CKEditor3.0的新方法
Jan 10 Javascript
jQuery LigerUI 插件介绍及使用之ligerDrag和ligerResizable示例代码打包
Apr 06 Javascript
正负小数点后两位浮点数实现原理及代码
Sep 06 Javascript
js表单中选择框值的获取及表单的序列化
Dec 17 Javascript
非常棒的jQuery图片轮播效果
Apr 17 Javascript
vue .sync修饰符的使用详解
Jun 15 Javascript
Element-UI中Upload上传文件前端缓存处理示例
Feb 21 Javascript
纯javascript实现选择框的全选与反选功能
Apr 08 Javascript
小程序实现左滑删除效果
Jul 25 Javascript
详解vue 自定义组件使用v-model 及探究其中原理
Oct 11 Javascript
JavaScript实现商品评价五星好评
Nov 30 Javascript
vue 对象添加或删除成员时无法实时更新的解决方法
May 01 #Javascript
JavaScript强制类型转换和隐式类型转换操作示例
May 01 #Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
May 01 #Javascript
Vue.extend实现挂载到实例上的方法
May 01 #Javascript
JS html事件冒泡和事件捕获操作示例
May 01 #Javascript
JS实现的贪吃蛇游戏案例详解
May 01 #Javascript
javascript原型链学习记录之继承实现方式分析
May 01 #Javascript
You might like
discuz论坛 用户登录 后台程序代码
2008/11/27 PHP
php实现图片添加描边字和马赛克的方法
2014/12/10 PHP
PHP实现链式操作的核心思想
2015/06/23 PHP
基于php实现随机合并数组并排序(原排序)
2015/11/26 PHP
Yii2.0 模态弹出框+ajax提交表单
2016/05/22 PHP
PHP处理二进制数据的实现方法
2016/06/13 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
javascript DOM编程实例(智播客学习)
2009/11/23 Javascript
js控制CSS样式属性语法对照表
2012/12/11 Javascript
图片无缝滚动代码(向左/向下/向上)
2013/04/10 Javascript
深入理解angularjs过滤器
2016/05/25 Javascript
41个Web开发者必须收藏的JavaScript实用技巧
2016/07/22 Javascript
Vue.js动态添加、删除选题的实例代码
2016/09/30 Javascript
javascript实现无法关闭的弹框
2016/11/27 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
2017/02/12 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
基于js 本地存储(详解)
2017/08/16 Javascript
Layui带搜索的下拉框的使用以及动态数据绑定方法
2019/09/28 Javascript
[19:54]夜魇凡尔赛茶话会 第一期02:看图识人
2021/03/11 DOTA
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
python实现对求解最长回文子串的动态规划算法
2018/06/02 Python
示例详解Python3 or Python2 两者之间的差异
2018/08/23 Python
Python 读取串口数据,动态绘图的示例
2019/07/02 Python
基于python2.7实现图形密码生成器的实例代码
2019/11/05 Python
在Python3.74+PyCharm2020.1 x64中安装使用Kivy的详细教程
2020/08/07 Python
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
农村产权制度改革实施方案
2014/03/21 职场文书
春节晚会主持词
2014/03/24 职场文书
卫校毕业生个人自我鉴定
2014/04/28 职场文书
走群众路线剖析材料
2014/10/09 职场文书
2015年学校医务室工作总结
2015/07/20 职场文书
心理学培训心得体会
2016/01/22 职场文书
2016学校先进党组织事迹材料
2016/02/29 职场文书
合同补充协议书
2016/03/24 职场文书
Windows中Redis安装配置流程并实现远程访问功能
2021/06/07 Redis
Java字符串逆序方法详情
2022/03/21 Java/Android