往期内容:
通过前面的学习, 我们了解到reactive
可以将一个普通对象转换成响应式对象.
那么, 接下来我们就详细研究一下这个函数.
研究函数主要从这样三个方面
- 输入, 也就是参数
- 作用, 做了什么
- 输出, 也就是返回值
- 参数: 只能是引用类型数据, 不能是值类型数据
- 作用: 创建传入对象的
深层
代理, 并返回代理后的对象 - 返回值: 一个Proxy代理对象
1) 深层代理
不管传入的对象存在多少层嵌套(对象套对象的情况), 每一层都具有响应性
示例
<!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="../node_modules/vue/dist/vue.global.js"></script>
</head>
<body>
<script>
const { reactive, effect } = Vue
const pState = reactive({
name: 'xiaoming',
age: 20,
gf: {
name: 'xiaomei',
city: {
name: 'wuhan',
},
},
})
effect(() => {
console.log(
`${pState.name}的女朋友叫${pState.gf.name}, 在${pState.gf.city.name}`
)
})
setTimeout(() => {
console.log('过了一段时间, 她去了beijing')
// 不管嵌套多少层, 都具有响应性
pState.gf.city.name = 'beijing'
}, 1000)
</script>
</body>
</html>
2) 重复代理
- 对同一个普通对象, 多次代理, 返回的结果唯一
- 对代理后的对象再次代理, 返回的结果唯一
以上, 可以理解为单例模式
, reactive
创建的代理对象只会存在一个
<!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="../node_modules/vue/dist/vue.global.js"></script>
</head>
<body>
<script>
const { reactive, effect } = Vue
const state = { name: 'xiaoming' }
const p1 = reactive(state)
const p2 = reactive(state)
// 对同一个对象多次代理, 返回的结果唯一
console.log(p1 === p2) // true
const p3 = reactive(p1)
// 对代理后的对象, 再次代理, 返回的结果唯一
console.log(p3 === p1) // true
</script>
</body>
</html>
3) 局限性
- 传入参数只能是对象
- 解构或者赋值操作会丢失响应性
示例1
解构赋值后的变量没有响应性
<!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="../node_modules/vue/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const { reactive, effect } = Vue
const pState = reactive({ name: 'xiaoming' })
// 对代理对象进行解构
let { name } = pState
effect(() => {
app.innerHTML = pState.name
})
setTimeout(() => {
name = 'xiaomei'
console.log('对解构后的name操作, 不会触发响应式')
}, 1000)
</script>
</body>
</html>
示例2
赋值操作丢失响应性
<!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="../node_modules/vue/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const { reactive, effect } = Vue
let todos = reactive([])
effect(() => {
app.innerHTML = JSON.stringify(todos)
})
// 模拟向接口请求
setTimeout(() => {
// 将接口返回的数据赋值给todos, 导致todos丢失了响应性
todos = [
{ id: 1, content: 'todo-1' },
{ id: 2, content: 'todo-2' },
]
}, 1000)
</script>
</body>
</html>