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 相关文章推荐
不错的asp中显示新闻的功能
Oct 13 Javascript
JSON 学习之JSON in JavaScript详细使用说明
Feb 23 Javascript
JS实现定时页面弹出类似QQ新闻的提示框
Nov 07 Javascript
jQuery实现滚动鼠标放大缩小图片的方法(附demo源码下载)
Mar 05 Javascript
javascript中BOM基础知识总结
Feb 14 Javascript
jQuery ajax请求struts action实现异步刷新
Apr 19 jQuery
JS中type="button"和type="submit"的区别
Jul 04 Javascript
Node.js学习之TCP/IP数据通讯(实例讲解)
Oct 11 Javascript
JavaScript函数定义方法实例详解
Mar 05 Javascript
element-ui组件table实现自定义筛选功能的示例代码
Mar 15 Javascript
在vue项目中使用codemirror插件实现代码编辑器功能
Aug 27 Javascript
基于原生js实现判断元素是否有指定class名
Jul 11 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
CPU步进是什么意思?i3-9100F B0步进和U0步进区别知识科普
2020/03/17 数码科技
搜索和替换文件或目录的一个好类--很实用
2006/10/09 PHP
Linux下将excel数据导入到mssql数据库中的方法
2010/02/08 PHP
PHP批量生成图片缩略图的方法
2015/06/18 PHP
php对xml文件的增删改查操作实现方法分析
2017/05/19 PHP
jquery validation插件表单验证的一个例子
2010/03/03 Javascript
制作高质量的JQuery Plugin 插件的方法
2010/04/20 Javascript
基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
2011/05/07 Javascript
js隐藏与显示回到顶部按钮及window.onscroll事件应用
2013/01/25 Javascript
jquery实现ajax提交form表单的方法总结
2014/03/03 Javascript
通过jquery 获取URL参数并进行转码
2014/08/18 Javascript
使用Sticker.js实现贴纸效果
2015/01/28 Javascript
javascript+html5实现仿flash滚动播放图片的方法
2015/04/27 Javascript
Jquery easyui开启行编辑模式增删改操作
2016/01/14 Javascript
jquery实现具有嵌套功能的选项卡
2016/02/12 Javascript
jquery的checkbox,radio,select等方法小结
2016/08/30 Javascript
详解使用vue实现tab 切换操作
2017/07/03 Javascript
JavaScript 有用的代码片段和 trick
2018/02/22 Javascript
vuejs点击class变化的实例
2018/09/05 Javascript
微信小程序使用websocket通讯的demo,含前后端代码,亲测可用
2019/05/22 Javascript
[01:13:18]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
python实现监控linux性能及进程消耗性能的方法
2014/07/25 Python
Python实现数据库编程方法详解
2015/06/09 Python
Python使用pandas处理CSV文件的实例讲解
2018/06/22 Python
Python常见MongoDB数据库操作实例总结
2018/07/24 Python
Django项目中实现使用qq第三方登录功能
2019/08/13 Python
Python 中@property的用法详解
2020/01/15 Python
Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
2020/04/20 Python
2013年军训通讯稿
2014/02/05 职场文书
工艺员岗位职责
2014/02/11 职场文书
校运会口号
2014/06/18 职场文书
车间主任岗位职责
2015/02/03 职场文书
2015年节能降耗工作总结
2015/05/22 职场文书
指导老师鉴定意见
2015/06/05 职场文书
2015年暑期社会实践总结
2015/07/13 职场文书
Python基础知识之变量的详解
2021/04/14 Python