Vue 数据响应式相关总结


Posted in Vue.js onJanuary 28, 2021

在说数据响应式之前,我们要解决一个很重要的问题,那就是Vue到底对data做了什么?先从getter和setter说起,我们用那个他们来对虚拟的属性进行读写。

getter和setter

有如下代码

let obj0 = {
 姓: "高",
 名: "圆圆",
 age: 18
};

// 需求一,得到姓名

let obj1 = {
 姓: "高",
 名: "圆圆",
 姓名() {
  return this.姓 + this.名;
 },
 age: 18
};

console.log("需求一:" + obj1.姓名());//高圆圆

此时我们log出来的结果是高圆圆,这个大家都能看懂,但是姓名后面的括号能删掉吗?不能,因为它是函数,那么我们怎么去掉括号呢?下面就有我们的需求二

// 需求二,姓名不要括号也能得出值

let obj2 = {
 姓: "高",
 名: "圆圆",
 get 姓名() {
  return this.姓 + this.名;
 },
 age: 18
};

console.log("需求二:" + obj2.姓名);//高圆圆

此时我们使用getter ,不加括号也能得出值。那么我们要怎么改变这个名字呢?

// 需求三:姓名可以被写

let obj3 = {
 姓: "高",
 名: "圆圆",
 get 姓名() {
  return this.姓 + this.名;
 },
 set 姓名(xxx){
  this.姓 = xxx[0]
  this.名 = xxx.slice(1)
 },
 age: 18
};

obj3.姓名 = '高媛媛'

console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`)//高媛媛

有get就有set,setter就是这样用的。我们用 属性值 = xxx 触发 set 函数,姓名就可以被写啦。但是我们在需求三中打出 console.log(obj3) 会得到如下图所示:

Vue 数据响应式相关总结

如图为什么会显示 姓名:(...) 呢? 这其实是一个get set,浏览器在显示这个姓名的时候就打印出 姓名:(...) ,这说明我们可以在需求三中对姓名进行读和写,但是并不存在一个叫做姓名的属性,而是有get和set来模拟对姓名进行的操作。

Object.defineProperty

在如上例子中,我们在定义对象的时候就直接使用get和set,但是如果对象已经被声明完了,那我们怎么继续加上get呢?我们就要用到Object.defineProperty,还是需求三,我们加入如下代码就可以在定义完之后再加get和set了:

var _xxx = 0
Object.defineProperty(obj3,'xxx',{
 get(){
  return _xxx
 },
 set(value){
  _xxx= value
 }
})

接下来我们就可以解决一开始的问题了:Vue到底对data做了什么?我们举几个例子看看:

let data0 = {
 n: 0
}

先声明一个data0,需求一:用 Object.defineProperty 定义 n:

let data1 = {}

Object.defineProperty(data1, 'n', {
 value: 0
})

console.log(`需求一:${data1.n}`)//需求一:0

需求二:n 不能小于 0:

let data2 = {}

data2._n = 0 // _n 用来偷偷存储 n 的值,默认为0

Object.defineProperty(data2, 'n', {
 get(){
  return this._n
 },
 set(value){
  if(value < 0) return
  this._n = value
 }
})

console.log(`需求二:${data2.n}`)//0
data2.n = -1
console.log(`需求二:${data2.n} 设置为 -1 失败`)//0设置为 -1 失败
data2.n = 1
console.log(`需求二:${data2.n} 设置为 1 成功`)//0设置为 1 成功

可是如果对方直接使用data2._n呢?我们能不能做到不在对象上暴露任何能够被访问的东西呢?这时候我们就要使用代理:

let data3 = proxy({ data:{n:0} }) // 括号里是匿名对象,无法访问

function proxy({data}){
 const obj = {}
 // 这里的 'n' 写死了,理论上应该遍历 data 的所有 key,这里做了简化
 // 因为我怕你们看不懂
 Object.defineProperty(obj, 'n', { 
  get(){
   return data.n
  },
  set(value){
   if(value<0)return
   data.n = value
  }
 })
 return obj // obj 就是代理
}

// data3 就是 obj
console.log(`需求三:${data3.n}`)
data3.n = -1
console.log(`需求三:${data3.n},设置为 -1 失败`)
data3.n = 1
console.log(`需求三:${data3.n},设置为 1 成功`)

可是如果不想用代理,要怎么做呢?

let myData = {n:0}
let data4 = proxy({ data:myData }) // 括号里是匿名对象,无法访问

// data3 就是 obj
console.log(`杠精:${data4.n}`)//0
myData.n = -1
console.log(`杠精:${data4.n},设置为 -1 失败了吗!?`)

现在这样还是能更改myData,所以我们又有一个需求:就算是用户擅自修改myData,也要拦截:

let myData5 = {n:0}
let data5 = proxy2({ data:myData5 }) // 括号里是匿名对象,无法访问

function proxy2({data}){
 // 这里的 'n' 写死了,理论上应该遍历 data 的所有 key,这里做了简化
 let value = data.n//保存开始的n
 Object.defineProperty(data, 'n', {//声明一个新的n
  get(){
   return value
  },
  set(newValue){
   if(newValue<0)return
   value = newValue
  }
 })

就加了上面几句,这几句话会监听 data

const obj = {}
 Object.defineProperty(obj, 'n', {
  get(){
   return data.n
  },
  set(value){
   if(value<0)return//这句话多余了
   data.n = value
  }
 })
 
 return obj // obj 就是代理
}

// data3 就是 obj
console.log(`需求五:${data5.n}`)//0
myData5.n = -1
console.log(`需求五:${data5.n},设置为 -1 失败了`)//0
myData5.n = 1
console.log(`需求五:${data5.n},设置为 1 成功了`)//1

当我们写vm = new Vue({data:myData})时,Vue做了两件事情:

  1. 让vm成为myData的代理(proxy),可以通过this访问vm
  2. 会对myData所有的属性进行监控,为了防止myData的属性变了,vm却不知道,知道了属性变化之后就可以调用render(data),UI就可以自动刷新

那么我们就可以回到标题了,什么是数据响应式呢?如果一个物体能够对外界的刺激做出反应,那么它就是响应式的。Vue的data是响应式的,const vm = new Vue({data:{n:0}})在这个代码中如果修改vm.n那么UI中的n就会做出相应的更新,Vue通过Object.defineProperty来实现数据响应式。
响应式网页又是什么呢?即如果改变窗口的大小,网页内容会做出相应的改变,那么这个网页就叫响应式网页。

以上就是Vue 数据响应式相关总结的详细内容,更多关于Vue 数据响应式的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
Vue项目利用axios请求接口下载excel
Nov 17 Vue.js
vue-router定义元信息meta操作
Dec 07 Vue.js
vue+vant 上传图片需要注意的地方
Jan 03 Vue.js
手写Vue源码之数据劫持示例详解
Jan 04 Vue.js
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
Vue实现图书管理案例
Jan 20 Vue.js
vue使用过滤器格式化日期
Jan 20 Vue.js
vue实现简易计算器功能
Jan 20 Vue.js
vue穿梭框实现上下移动
Jan 29 Vue.js
vue组件的路由高亮问题解决方法
May 11 Vue.js
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
Nov 27 Vue.js
vue实现Toast组件轻提示
Apr 10 Vue.js
vue.js实现点击图标放大离开时缩小的代码
Jan 27 #Vue.js
vscode自定义vue模板的实现
Jan 27 #Vue.js
vue+echarts实现中国地图流动效果(步骤详解)
Jan 27 #Vue.js
vue3 watch和watchEffect的使用以及有哪些区别
Jan 26 #Vue.js
vue实现轮播图帧率播放
Jan 26 #Vue.js
vue 组件基础知识总结
Jan 26 #Vue.js
深入了解Vue动态组件和异步组件
Jan 26 #Vue.js
You might like
PHP关联链接常用代码
2012/11/05 PHP
如何利用php array_multisort函数 对数据库结果进行复杂排序
2013/06/08 PHP
destoon实现不同会员组公司名称显示不同的颜色的方法
2014/08/22 PHP
php的mssql数据库连接类实例
2014/11/28 PHP
PHP实现获取并生成数据库字典的方法
2016/05/04 PHP
jQuery选择没有colspan属性的td的代码
2010/07/06 Javascript
jquery 文本上下无缝滚动,鼠标放上去就停止 小例子
2013/06/05 Javascript
Jquery通过Ajax方式来提交Form表单的具体实现
2013/11/07 Javascript
jquery性能优化高级技巧
2015/08/24 Javascript
JavaScript学习总结之JS、AJAX应用
2016/01/29 Javascript
js生成随机颜色方法代码分享(三种)
2016/12/29 Javascript
Vue中封装input组件的实例详解
2017/10/17 Javascript
Vue DevTools调试工具的使用
2017/12/05 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
原生JS实现前端本地文件上传
2018/09/08 Javascript
Vue 实现从文件中获取文本信息的方法详解
2019/10/16 Javascript
[04:44]显微镜下的DOTA2第二期——你所没有注意到的细节
2014/06/20 DOTA
python 字符串split的用法分享
2013/03/23 Python
Python中输出ASCII大文字、艺术字、字符字小技巧
2015/04/28 Python
python爬虫_微信公众号推送信息爬取的实例
2017/10/23 Python
在Python中给Nan值更改为0的方法
2018/10/30 Python
python实现淘宝秒杀脚本
2020/06/23 Python
Python环境Pillow( PIL )图像处理工具使用解析
2019/09/12 Python
python实现从wind导入数据
2019/12/03 Python
Python如何将模块打包并发布
2020/08/30 Python
Pycharm 设置默认解释器路径和编码格式的操作
2021/02/05 Python
python爬虫今日热榜数据到txt文件的源码
2021/02/23 Python
瑞典廉价机票预订网站:Seat24
2018/06/19 全球购物
英国第一职业高尔夫商店:Clickgolf.co.uk
2020/11/18 全球购物
护理专业应届毕业生推荐信
2013/11/15 职场文书
市场专员岗位职责
2014/02/14 职场文书
2014年五一劳动节社区活动总结
2014/04/14 职场文书
会计实训报告范文
2014/11/04 职场文书
表扬稿范文
2015/01/17 职场文书
云台山导游词
2015/02/03 职场文书
企业党建工作总结2015
2015/05/26 职场文书