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的mixin策略
Nov 19 Vue.js
Vue router安装及使用方法解析
Dec 02 Vue.js
vue使用exif获取图片旋转,压缩的示例代码
Dec 11 Vue.js
vue实现滚动鼠标滚轮切换页面
Dec 13 Vue.js
Vue实现点击当前行变色
Dec 14 Vue.js
Vue仿Bibibili首页的问题
Jan 21 Vue.js
如何在vue中使用video.js播放m3u8格式的视频
Feb 01 Vue.js
vue浏览器返回监听的具体步骤
Feb 03 Vue.js
vue-cli 3如何使用vue-bootstrap-datetimepicker日期插件
Feb 20 Vue.js
Vue通过懒加载提升页面响应速度
May 10 Vue.js
Vue监视数据的原理详解
Feb 24 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提示Cannot modify header information - headers already sent by解决方法
2014/09/22 PHP
PHP框架自动加载类文件原理详解
2017/06/06 PHP
jquery 可拖拽的窗体控件实现代码
2010/03/21 Javascript
Jquery图片滚动与幻灯片的实例代码
2013/04/08 Javascript
JavaScript事件委托技术实例分析
2015/02/06 Javascript
Bootstrap Paginator分页插件使用方法详解
2016/05/30 Javascript
原生js代码实现图片放大境效果
2016/10/30 Javascript
canvas实现图像截取功能
2017/02/06 Javascript
vue实现表格数据的增删改查
2017/07/10 Javascript
利用node.js实现自动生成前端项目组件的方法详解
2017/07/12 Javascript
使用Electron构建React+Webpack桌面应用的方法
2017/12/15 Javascript
vue组件数据传递、父子组件数据获取,slot,router路由功能示例
2019/03/19 Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
2019/05/01 Javascript
详解package.json版本号规则
2019/08/01 Javascript
解决echarts echarts数据动态更新和dataZoom被重置问题
2020/07/20 Javascript
[50:28]LGD女子学院第三期 DOTA2复仇之魂教学
2013/12/24 DOTA
django使用JWT保存用户登录信息
2020/04/22 Python
python 实现aes256加密
2020/11/27 Python
pycharm实现猜数游戏
2020/12/07 Python
详解Python中@staticmethod和@classmethod区别及使用示例代码
2020/12/14 Python
css3实现文字扫光渐变动画效果的示例
2017/11/07 HTML / CSS
HTML5之SVG 2D入门4—笔画与填充
2013/01/30 HTML / CSS
Kathmandu英国网站:新西兰户外运动品牌
2017/03/27 全球购物
MyBag中文网:英国著名的时尚包袋电商零售网站
2020/07/31 全球购物
物理研修随笔感言
2014/02/14 职场文书
房地产财务部员工岗位职责
2014/03/12 职场文书
银行内勤岗位职责
2014/04/09 职场文书
中等生评语大全
2014/05/04 职场文书
会计专业求职信
2014/08/10 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
2014年学校办公室工作总结
2014/12/19 职场文书
爱晚亭导游词
2015/02/09 职场文书
社区母亲节活动总结
2015/02/10 职场文书
2015年纪检监察工作总结
2015/04/08 职场文书
2015年保洁工作总结范文
2015/04/28 职场文书
刮痧观后感
2015/06/05 职场文书