我是靠谱客的博主 要减肥板栗,这篇文章主要介绍Vue响应式原理一.深入响应式原理二.Object.defineProperty属性三.检测变化的注意事项四.实现一个响应式五:Object.defineProperty的一些参数六.封装一个函数,监听对象的属性值变化。,现在分享给大家,希望可以做个参考。

一.深入响应式原理

Vue最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的JavaScrpit对象。而当你修改他们时,视图会进行更新。这使得状态管理非常简单直接,不过理解其工作原理同样重要,这样你可以避免一些常见的问题。接下来我们一起探究下吧。

二.Object.defineProperty属性

当你把普通的JavaScrpit对象传入Vue实例作为data选项,Vue将遍历此对象所有的property,并且使用Object.defineProperty 把这些property全部转为getter/setter。Object.defineProperty是ES5中一个无法shim的特性,这也就是Vue不支持IE8以及更低版本浏览器的原因。

关于对shim的解释

Vue响应式原理中:Object.defineProperty是Es5中无法shim的特性,那么这里的shim是什么呢?
定义:shim可以将新的API引入到旧的环境中,而且仅靠就环境中已有的手段实现。

这些getter/setter对用户来说是不可见的,但是在内部他们让Vue能够追踪依赖,在property被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对getter/setter的格式化并不同,所以建议安装vue-devtools来获取对检查数据更加友好的用户界面。

每个组件实例都对应watcher实例,它会在组件渲染的过程中把'接触'过的数据,property记录为依赖。之后当依赖项的setter触发时,会通知watcher,从而使它关联的组件重新渲染。 

图示:

三.检测变化的注意事项

(1)Vue不能检测数组和对象的变化

由于JavaScrpit的限制,Vue不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应式。

(2)对于对象

Vue无法检测property的添加或移除。由于Vue会在初始化实例时对property执行getter/setter转化,所以property必须在data对象上存在才能让Vue将它转化为响应式的。

需求要在一个对象里面添加一个属性

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./vue.js"></script> </head> <body> <div id="app"> <h1>{{obj.a}}</h1> <h1>{{obj.c}}</h1> <button @click="fn"></button> </div> <script> const app=new Vue({ el:"#app", data() { return { obj:{a:1} } }, methods: { fn(){ // this.obj.a=10 // 直接修改原始的对象是可以修改的 // this.obj.c=10 // 但是想要直接给对象添加一个属性是不可以的 // this.$set(this.obj,'c',10) 可以利用官方提供的api } }, }) </script> </body> </html>

在原始有的对象里直接通过:

  // this.obj.c=10,添加一个属是无效的,

但是可以提供Vue提供的api:

  // this.$set(this.obj,'c',10) 

剖析:this.$set(要添加的对象,属性名(要用字符串包裹起来),属性值)

(3)对于数组

1.对于数组除了一些数组的api:push,pop,unshift,shift等api是响应的之外

2.也可以使用this.$set提供的这个api,在数组中的配置如下:

this.$set(要修改的数组,索引的位置,要添加的元素)

四.实现一个响应式

1.代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- 显示obj.a的值 --> 1 </div> <script> var obj={a:1} Object.defineProperty(obj,'a',{ get:function(){ console.log(`有人对a属性进行了访问`); }, set:function(newVal){ document.getElementById('app').innerHTML=newVal } }) </script> </body> </html>

2.图示

当有人访问到了a属性就会触发get这个函数

 

当有人给a进行赋值的时候就会触发set这个函数

 这个时候可以看见左边的视图发生了改变,符合Vue双向数据绑定的原理,即:数据------------视图,也可以的到的是newVal的值是我们输入的值是10。

五:Object.defineProperty的一些参数

1.Value

复制代码
1
2
3
4
5
6
7
8
9
let obj={ a:1 } Object.defineProperty(obj,'c',{ value:10 }) console.log(obj);

图示:

可以看出obj对象里面多出了c属性并且它的值为10,相当于obj.c=10;

2.writable

定于:如果writable的值为false的话,则里面的值是不可以进行修改的、

代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ a:1 } Object.defineProperty(obj,'c',{ writable:false, value:10 }) obj.a=1000 obj.c=50 // 用defineProperty修改里面的值是没用效果的 console.log(obj); </script> </body> </html>

图示:

3.configurable

1.configurable:false,表示不能被删除,也不能被重定义。

2.代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ a:1 } Object.defineProperty(obj,'c',{ // writable:false, value:10, configurable:false }) delete obj.a //可以被删除 delete obj.c //不能被删除 // 用defineProperty修改里面的值是没用效果的 console.log(obj); </script> </body> </html>

3.图示:

4.不能被重定义:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ a:1 } Object.defineProperty(obj,'c',{ // writable:false, value:10, configurable:false }) // 不能重新进行定义 Object.defineProperty(obj,'c',{ value:30 }) console.log(obj); </script> </body> </html>

图示:

4.enumerable

定义:如果该值为false的话,则表示是不可以进行枚举的。

代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> var person = {} Object.defineProperty(person,'name',{ configurable:false,//能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true enumerable:false,//对象属性是否可通过for-in循环,flase为不可循环,默认值为true writable:false,//对象属性是否可修改,flase为不可修改,默认值为true value:'xiaoming' //对象属性的默认值,默认值为undefined }); for(var i in person){ console.log(person[i]) //无结果,不可循环 } </script> </body> </html>

图示:当为enumerable的时候可以遍历出来

六.封装一个函数,监听对象的属性值变化。

1.代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={a:1,b:2,c:3} let newObj={} for (let key in obj) { Object.defineProperty(newObj,key,{ set:function(newVal){ console.log(`有人修改了${key},新值是${newVal}`); obj[key]=newVal }, get:function(){ return obj[key] } }) } </script> </body> </html>

2.用了set会被当成拦截器,获取不了值,需要设置变量来解决问题

3.图示:

 七.扩展obj[`key`],obj[key],obj.key的用法和区别

代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ name:'卡卡西' } console.log(obj[`name`]); console.log(obj.name); for (let key in obj) { console.log(obj[key]); } </script> </body> </html>

对象的属性名是一个字符

验证:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ name:'卡卡西', age:20 } console.log(obj[`name`]); // 所以取出对象属性值的时候,还可以这样写obj[`name`] for (let key in obj) { console.log(typeof key); } </script> </body> </html>

图示:

 

可以看出分为两种进行使用:

去除对象的属性值:对象.属性名,对象.[`属性名`]

如果需要进行枚举的话:对象[属性名]

列如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj={ name:'卡卡西', age:20 } for (const key in obj) { console.log(key); console.log(obj[key]); } </script> </body> </html>

最后

以上就是要减肥板栗最近收集整理的关于Vue响应式原理一.深入响应式原理二.Object.defineProperty属性三.检测变化的注意事项四.实现一个响应式五:Object.defineProperty的一些参数六.封装一个函数,监听对象的属性值变化。的全部内容,更多相关Vue响应式原理一.深入响应式原理二.Object.defineProperty属性三.检测变化内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部