前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >44·灵魂前端工程师养成-前端框架Vue数据响应式

44·灵魂前端工程师养成-前端框架Vue数据响应式

作者头像
DriverZeng
发布2022-11-08 17:10:35
8200
发布2022-11-08 17:10:35
举报

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


Vue对data做了什么


小实验

data变了

codesandbox示例代码:TP

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

const myData = {
  n:0
}

console.log(myData)

const vm = new Vue({
  data:myData,
  template:`
    <div>
      {{n}}
      <button @click="add">
        +10
      </button>
    </div>
  `,
  methods:{
    add(){
      this.n += 10
    }
  }
}).$mount("#app")

setTimeout(()=>{
  myData.n+=10
  console.log(myData)
  console.log(vm)
},3000)

我们总共打印了两次myData

第一次打印是{n:0}

然后3秒钟之后再打印一次,应该是{n:10}对吧

myData变成了一个奇奇怪怪的东西

一开始{n:0},传给new Vue之后立马变成了{n:(...)}

{n:(...)}这是个什么玩意?为什么表现和{n:0}一致?

我们需要先学习一下ES6的gettersetter

codesandbox示例代码:TP

代码语言:javascript
复制
let obj0 = {
  姓: "邓",
  名: "紫琪",
  age: 18
}

// 需求一:得到姓名

let obj1 = {
  姓: "邓",
  名: "紫琪",
  姓名(){
    return this.姓 + this.名
  },
  age: 18
}

console.log('需求一:' + obj1.姓名())

// 姓名后面的括号能删除么?
// 不能,因为他是一个函数
// 如何去掉括号?

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

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.名}`)
//总结:setter就是这样赢的。 用 = xxx 触发set函数

我们把obj3打印出来,看看结果

代码语言:javascript
复制
console.log(obj3)

可以发现... 有个姓名:(...) 和刚才的{n:(...)}是不是有点蛛丝马迹了。这个姓名,不是真实的姓名,浏览器,允许读写,所以模拟姓名的操作。

所以{n:(...)}并不存在这样的一个n,只是浏览器模拟n的操作。

那么为什么要{n:(...)}用这种方法呢?

我们又要了解一个新的知识Object.defineProperty

Object.defineProperty

继续做实验:TP

我们现在已经把obj3定义完了,那么我们调用的时候,如果想要get age,怎么办?我们不可能去修改定义的部分,如果这个功能是别的开发写好的代码给你的,你不可能改别人的代码吧?所以此时,我们需要用到Object.defineProperty

代码语言:javascript
复制
let obj0 = {
  姓: "邓",
  名: "紫琪",
  age: 18
};

// 需求一:得到姓名

let obj1 = {
  姓: "邓",
  名: "紫琪",
  姓名() {
    return this.姓 + this.名;
  },
  age: 18
};

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

// 姓名后面的括号能删除么?
// 不能,因为他是一个函数
// 如何去掉括号?

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

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
};

var _xxx = 0

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

obj3.姓名 = "曾老湿";
console.log(`需求三:姓:${obj3.姓},名:${obj3.名}`);
//总结:setter就是这样赢的。 用 = xxx 触发set函数

这就是Object.defineProperty,如果已经定义好的对象,你想给它添加虚拟属性,那么就使用这种方法。

Vue对data做的事情总结


Object.define.Property

可以 给对象添加属性value 可以 给对象添加getter/setter getter/setter用于对属性的读写进行监控


代理(设计模式)

对myData对象 的属性读写,全权由另一个对象vm负责 那么vm就是myData的代理 比如myData.n不用,偏要用vm.n来操作myData.n


vm=new Vue({data:myData})

1.会让vm称为myData的代理(proxy) 2.会对myData的所有属性进行监控

为什么要监控,为了防止世界被破坏,为了守护世界的和平...对不起,乱入了,为了防止myData的属性变了,vm不知道

vm知道了又如何?知道属性变了就可以调用render(data)呀!!!UI=render(data)

Vue的data存在bug


数据响应式

什么是数据响应式?

我打你一拳,你会喊疼,那你就是响应式。 若一个物体能对外界的刺激做出反应,它就是响应式


Vue的data是响应式

const vm = new Vue({data:{n:0}}) 我如果修改vm.n,那么UI中的n就会来响应我 Vue2通过Object.defineProperty来是想数据响应式


响应式网页是啥? 如果我改变窗口的大小,网页内容就会做出响应,那就是响应式网页。 比如:https://www.smashingmagazine.com/ 但是要注意,用户没事不会拖动网页大小。


data的bug

Object.defineProperty的问题 Object.defineProperty(obj,'n',{...}) 必须要有一个'n',才能监听&代理obj.n对吧 如果前端开发者比较"睿智",没有给n怎么办?

示例一:Vue会给出一个警告 TP

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
    data: {},
    template: `
    <div>{{n}}</div>
  `,
}).$mount("#app");

示例二:Vue只会检查第一层属性,我们有方法绕过他 TP

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
  data:{
    obj:{
      a:0
    }
  },
  template:`
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods:{
    setB(){
      this.obj.b = 1  //请问,页面会显示1嘛?
    }
  }
}).$mount("#app")

这样一来,vue就没有警告了。

此时如果我店家set b,请问图中会显示1嘛? 答案是:不会 因为,Vue再牛逼,它也不可能监听一个不存在的字符串 ,obj.b 一开始就不存在,如何监听?不能把所有字符串都监听一遍吧?

解决办法 1.那我把key都声明好,后面不再加属性不就行了 2.使用Vue.set或者this.$set

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
  data: {
    obj: {
      a: 0
    }
  },
  template: `
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods: {
    setB() {
      //this.obj.b = 1; //请问,页面会显示1嘛?
      Vue.set(this.obj,'b',1)
      this.$set(this.obj,'b',1)
    }
  }
}).$mount("#app");

Vue.set 和 this.$set

作用: 1.新增key 2.自动创建代理和监听(如果没创建就自动创建) 3.触发UI更新(但不会立刻更新,异步更新)

data中数组变异


data中有数组怎么办?

你没法提前声明所有key 示例1:数组的长度可以一直增加,下标就是key 你没有办法提前把数组的key都声明出来 Vue也不能检测对你新增了下标 难道每次改数组都要用Vue.set或者this.$set

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      this.array[3] = "d"; //请问页面会显示d嘛?
      //等下,你为什么不用this.array.puysh('d')
    }
  }
}).$mount("#app");

页面中,会显示d嘛?答案是不会,因为这个数组就相当于是 array:{0:'a',1:'b',2:'c'},你只设置了0,1,2所以Vue监听不到3,那这个时候我们用set可不可以呢?

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      // this.array[3] = "d"; //请问页面会显示d嘛?
      this.$set(this.array,3,'d')
      //等下,你为什么不用this.array.puysh('d')
    }
  }
}).$mount("#app");

尤雨溪的做法

篡改数组的API,见文档中异更方法章节

这7个API都会被Vue篡改,调用后会更新UI

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      // this.array[3] = "d"; //请问页面会显示d嘛?
      // this.$set(this.array,3,'d')
      //等下,你为什么不用this.array.puysh('d')
      this.array.push('d')
    }
  }
}).$mount("#app");

怎么篡改的?ES6写法

代码语言:javascript
复制
class VueArray extends Array{
  push(...args){
    const oldLength = this.length //this就是当前数组
    super.push(...args)
    console.log('你push了')
    for(let i = oldLength;i<this.length;i++){
      Vue.set(this,i,this[i]) //将每个新增的key都告诉Vue
    }
  }
}

注意:者不代表Vue的真实实现,此代码仅用于教学目的,实际上我没看过相关源码

新增key总结


对象新增的key

Vue没有办法实现监听和代理 要使用set来新增key,创建监听和代理,更新UI 最好前提把属性都写出来,不要新增key 但数组做不到"不新增key"


数组新增的key

也可以使用set来新增key,更新UI(set新增key不会创建监听和代理) 不过尤雨溪篡改了7个API方便你对数组进行增删 这7个API会自动处理监听和代理,并更新UI

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Vue对data做了什么
  • Vue对data做的事情总结
  • Vue的data存在bug
  • data中数组变异
  • 新增key总结
相关产品与服务
堡垒机
腾讯云堡垒机(Bastion Host,BH)可为您的 IT 资产提供代理访问以及智能操作审计服务,为客户构建一套完善的事前预防、事中监控、事后审计安全管理体系,助力企业顺利通过等保测评。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档