🌵 作者主页:仙女不下凡
🌵 前言介绍:以下👇 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!
🌵 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
🌵 学习理由:相信有很多小伙伴有个疑问,数据代理这个概念其实在开发中并不直接使用,为什么还要了解呢?相信很多小伙伴并不想只把前端开发的能力停留在会用这个层面上,了解这个原理有利于解决开发跟多疑问,同时这个原理也是面试的经典问题。
💛1.Object.defineProperty()方法
🌼学习数据代理之前先复习一个方法Object.defineProperty
,使用该方法给对象添加属性能够有更加细致的控制 🔊比如:可以控制追加在对象中的元素是否可以用forEach()
等遍历;添加之后是否可以删除等,所以在Vue
中数据劫持、数据代理、计算属性都利用了该方法。
🌼下面就提两个需求简单体会一下Object.defineProperty()
的实际应用。
🔔需求一:添加age
属性并控制是否可以被枚举等功能👇
🔔需求二:添加number
的值到height
属性中,且number
改变时height
的值同步更改👇
<script type="text/javascript">
let number = 160
let person = {
name: '张三',
sex: '男'
}
Object.defineProperty(person,'age',{
value:18,
enumerable:true, /控制属性是否可以枚举, 默认值是false/
writable:true, /控制属性是否可以被修改, 默认值是false/
configurable:true, /控制属性是否可以被删除, 默认是false/
})
Object.defineProperty(person,'height',{
/当读取person的height属性时, get函数就会被调用, 且返回值就是height的值/
get:function(){ return number}, //这样height值就可以时时随着number改变, 简写get(){}
/当修改person的height属性时, setter就会被调用, 且收到修改的具体值/
set(val){ console.log('收到height具体值为',val) }
})
</script>
🌼get函数
别称是getter
,set函数
别称是setter
。
💛2.数据代理基本理念
🌼什么是数据代理?:通过一个对象代理对另一个对象中属性的操作(读/写)。
<script type="text/javascript">
/用一段代码解释一下什么是数据代理, 将obj2数据交给obj代理/
let obj = {x;100};
let obj2 = {y:200};
Object.defineProperty(obj2,'x',{
get(){ return obj.x },
set(value){ obj.x = value }
})
</script>
💛3.数据代理在vue的data中的应用
💦Ⅰ.验证data中的数据代理
🌼下面就写了一段代码来验证vue
中存在的数据代理是否成立,即图中setter
与getter
两条线,如下图中💙蓝色和💗红色的线。
<body>
<div id="root">
<h2>学校名称: {{name}}</h2>
<h2>学校地址: {{address}}</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; /阻止vue在启动时生成生产提示/
const vm = new Vue({
el:'#root',
data:{ /vm._data就是这个里面的data,它做了一个数据劫持/
name:'尚硅谷',
address:'上海'
}
})
console.log(vm,"打印vm为了便于观察");
/执行结果为Vue实例, 其中data中每个数据(如name,address)都有自己的getter与setter/
</script>
🌼下面的代码验证了vm._data
就是这个里面的data
,而在vm._data
内部做了一个数据劫持。
<body>
<div id="root">
<h2>学校名称: {{name}}</h2> /所以如果vue中没做数据代理{{name}}就得写成{{_data.name}}/
<h2>学校地址: {{address}}</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; /阻止vue在启动时生成生产提示/
let data = {
name:'尚硅谷',
address:'上海'
}
const vm = new Vue({
el:'#root',
data
})
console.log(vm._data === data);
/执行结果为true, 所以vm._data就是data, 蓝色的线就可以验证了/
</script>
🌼如果vue
中没做数据代理{{name}}
就得写成{{_data.name}}
,令编码更加方便,这就是数据代理在Vue
中的实际应用意义。
🌼因为当我们修改data
中的值,页面上面的显示值同步修改,这就验证了红色线可以成立。
💦Ⅱ.Vue数据代理过程图形演示
🌼🌼数据代理生成过程🌼🌼
❶当我们声明vue
实例对象之后,即vm
;
❷vm
中会生成各种配置对象options
,其中options
包含了_data
;
❸由于底层代码的支持会自动给_data
中每个数据,在_data
的外部(即同级)添加对应新的元素(即数据代理),如上图☝🏻中的name、address
,同时每个name、address
中都会有setter、getter
函数。
vm {
......
_data:{ __ob__: Observer }, /这里面存着name与address的值/
......
name: '尚硅谷',
address: '上海',
......
get name: f proxyGetter,
set name: f proxySetter,
get address: f proxyGetter,
set address: f proxySetter, /这个就是添加的getter与setter方法/
......
}
💦Ⅲ.总结
🌼⑴Vue
中的数据代理:通过vm
对象代理data
对象中属性的操作(读/写)。
🌼⑵Vue
中数据代理的好处:更加方便的操作data
中的数据。
🌼⑶基本原理: ❶通过Object.defineProperty()
把data
对象中所有属性添加到vm
上; ❷为每一个添加到vm
上的属性,都指定一个getter/setter
; ❸在getter/setter
内部去操作(读/写)data
中对应的属性。
💛4.数据代理在计算属性component中的应用
💭💭💭思考一个问题,已经有methods
与{{}}
插值表达式,为什么还有components
?有什么存在的意义呢?
👉解答:首先插值表达式{{}}
,在vue
定义原则中曾注明只包含简单的表达式;其次当data
中数据改变就会重新解析模板,也会再次调用相关方法methods
,导致效率不高。
🌼 计算属性定义:要用的属性不存在,要通过已有属性计算得来。
🌼 计算属性原理:底层借助了Object.defineproperty()
提供的getter
和setter
。
🌼 计算属性中的 get
函数什么时候执行? ❶初次读取时会执行一次❷当依赖的数据发生变化时会被再次调用。
🌼 计算属性的优势:与methods
实现相比,内部有 缓存机制(复用),效率更高,调试更方便。
/什么是缓存解释一下/
{{fullName}} /这里fullName多次复用了, fullName直接调用缓存的info的值, 这个就是缓存机制/
{{fullName}}
{{fullName}}
computed:{
fullName:{
/get作用:当有人读取fullName时,get就会被调用,且返回值就作为fullName的值/;
/get什么时候被调用? ❶初次读取fristName时 ❷所依赖的数据发生改变时/
get(){return this.info = 2},
set(){}, /set什么时候调用? 当fullName被修改时调用, 不是必须写/
}
}
/如果不用写set(),直接简写/
fullName:{return this.info = 2}