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+iview分页组件的封装
Nov 17 Vue.js
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
vue element-ul实现展开和收起功能的实例代码
Nov 25 Vue.js
vue 通过base64实现图片下载功能
Dec 19 Vue.js
Vue.extend 登录注册模态框的实现
Dec 29 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
vue集成一个支持图片缩放拖拽的富文本编辑器
Jan 29 Vue.js
如何管理Vue中的缓存页面
Feb 06 Vue.js
Vue全家桶入门基础教程
May 14 Vue.js
Vue Element-ui表单校验规则实现
Jul 09 Vue.js
vue+echarts实现多条折线图
Mar 21 Vue.js
vue实力踩坑之push当前页无效
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
类的另类用法--数据的封装
2006/10/09 PHP
使用 MySQL Date/Time 类型
2008/03/26 PHP
curl和libcurl的区别简介
2015/07/01 PHP
php-msf源码详解
2017/12/25 PHP
laravel多条件查询方法(and,or嵌套查询)
2019/10/09 PHP
PHP如何开启Opcache功能提升程序处理效率
2020/04/27 PHP
window.addEventListener来解决让一个js事件执行多个函数
2012/12/26 Javascript
九种js弹出对话框的方法总结
2013/03/12 Javascript
原生javascript模仿win8等待提示圆圈进度条
2014/04/24 Javascript
JS使用eval()动态创建变量的方法
2016/06/03 Javascript
跨域请求的完美解决方法(JSONP, CORS)
2016/06/12 Javascript
原生js开发的日历插件
2017/02/04 Javascript
JS实现移动端实时监听输入框变化的实例代码
2017/04/12 Javascript
编写更好的JavaScript条件式和匹配条件的技巧(小结)
2019/06/27 Javascript
js实现无缝轮播图效果
2020/03/09 Javascript
微信小程序实现点击生成随机验证码
2020/09/09 Javascript
python使用cookielib库示例分享
2014/03/03 Python
Python 内置函数complex详解
2016/10/23 Python
Python编程使用*解包和itertools.product()求笛卡尔积的方法
2017/12/18 Python
详解Python中 sys.argv[]的用法简明解释
2017/12/20 Python
python 匹配url中是否存在IP地址的方法
2018/06/04 Python
python实现机器学习之元线性回归
2018/09/06 Python
python实现批量视频分帧、保存视频帧
2019/05/31 Python
关于PyTorch 自动求导机制详解
2019/08/18 Python
Python爬虫:Request Payload和Form Data的简单区别说明
2020/04/30 Python
使用Python项目生成所有依赖包的清单方式
2020/07/13 Python
PyCharm最新激活码(2020/10/27全网最新)
2020/10/27 Python
Baby Tulai澳大利亚:美国婴儿背带品牌
2018/10/15 全球购物
试用期员工考核制度
2014/01/22 职场文书
先进集体事迹材料
2014/02/17 职场文书
土木工程师职业规划范文
2014/03/07 职场文书
大学生全国两会报告感想
2014/03/17 职场文书
学校创先争优活动总结
2014/08/28 职场文书
合伙经营协议书范本(通用版)
2014/12/03 职场文书
客房领班岗位职责
2015/02/11 职场文书
React中的Context应用场景分析
2021/06/11 Javascript