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-drawer-layout实现手势滑出菜单栏
Nov 19 Vue.js
vue实现表格合并功能
Dec 01 Vue.js
Vue router传递参数并解决刷新页面参数丢失问题
Dec 02 Vue.js
vue实现滚动鼠标滚轮切换页面
Dec 13 Vue.js
Vue解决移动端弹窗滚动穿透问题
Dec 15 Vue.js
Vue 组件注册全解析
Dec 17 Vue.js
vue实现登录、注册、退出、跳转等功能
Dec 23 Vue.js
如何理解Vue前后端数据交互与显示
May 10 Vue.js
Element-ui Layout布局(Row和Col组件)的实现
Dec 06 Vue.js
vue组件vue-esign实现电子签名
Apr 21 Vue.js
VUE解决跨域问题Access to XMLHttpRequest at
May 06 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
星际争霸教主Flash的ID由来:你永远不会知道他之前的ID是www!
2019/01/18 星际争霸
PHP去掉从word直接粘贴过来的没有用格式的函数
2012/10/29 PHP
为PHP5.4开启Zend OPCode缓存
2014/12/26 PHP
php基于websocket搭建简易聊天室实践
2016/10/24 PHP
Apache+PHP+MySQL搭建PHP开发环境图文教程
2020/08/06 PHP
javascript中的继承实例代码
2011/04/27 Javascript
node.js不得不说的12点内容
2014/07/14 Javascript
详解AngularJS实现表单验证
2015/12/10 Javascript
JS实时弹出新消息提示框并有提示音响起的实现代码
2016/04/20 Javascript
jQuery弹出层后禁用底部滚动条(移动端关闭回到原位置)
2016/08/29 Javascript
ES6概念 Symbol.keyFor()方法
2016/12/25 Javascript
原生js实现简单的Ripple按钮实例代码
2017/03/24 Javascript
改变vue请求过来的数据中的某一项值的方法(详解)
2018/03/08 Javascript
jQuery实现的简单对话框拖动功能示例
2018/06/05 jQuery
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
python操作日期和时间的方法
2014/03/11 Python
python实现简单温度转换的方法
2015/03/13 Python
python实现端口转发器的方法
2015/03/13 Python
在 Python 应用中使用 MongoDB的方法
2017/01/05 Python
Python实现两款计算器功能示例
2017/12/19 Python
解决Python print 输出文本显示 gbk 编码错误问题
2018/07/13 Python
python 实现调用子文件下的模块方法
2018/12/07 Python
PyTorch实现更新部分网络,其他不更新
2019/12/31 Python
Keras之fit_generator与train_on_batch用法
2020/06/17 Python
Python实现自动装机功能案例分析
2020/10/22 Python
css3.0新属性效果在ie下的解决方案
2010/05/10 HTML / CSS
利用CSS3实现开门效果实例源码
2016/08/22 HTML / CSS
CSS3 animation ? steps 函数详解
2019/08/30 HTML / CSS
船舶专业个人求职信范文
2014/01/02 职场文书
写给保洁员表扬信
2014/01/08 职场文书
会计助理岗位职责
2014/02/17 职场文书
拉歌口号大全
2014/06/13 职场文书
授权收款委托书
2014/09/23 职场文书
2015年员工试用期工作总结
2015/05/28 职场文书
2016年秋季运动会加油稿
2015/12/21 职场文书