Object.defineProperty()
Object.defineProperty()的基本属性和实现简单的数据代理(也叫数据劫持)
// 使number数据和person.age相互关联
let number = 18
let person = {
name: 'zhangsan',
sex: 'male'
}
// 给person对象添加age属性
Object.defineProperty(person, 'age', {
// value: 18,
// enumerable: true, // 控制属性是否可以枚举,默认为false
// writable: true, // 控制属性是否可以被修改,默认为false
// configurable: true, // 控制属性是否可以被删除,默认为false
// 当有人读取person中的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get() {
return number
},
// 当有人修改person中的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(val) {
number = val
}
})
console控制台图示
仔细看下图会发现这里其实比正常的对象多出了get()和set()两个方法
另外要注意这里的age属性值age: (...)
和其他属性值的区别,其实用Vue的时候经常会见到这种格式,只有点一下才会显示出age的值,这是因为这里的age是用get()做了数据劫持,只有在访问的时候才会获取新的值,Vue中就是用这样的方式实现监听数据改变的
Vue中监测数据的原理
<div id="app">{{name}}</div>
const vm = new Vue({
el: '#app',
data: {
name: 'zhangsan'
}
})
vm实例data
中的name
数据之所以能用this.name
访问(这里的this就是vm实例对象),实际上是Vue在vm实例上和vm._data
做了数据代理(响应式),访问vm.name
和vm._data.name
是一样的,如下图
模拟Vue监测数据的一个简单例子
const data = {
name: 'zhangsan'
}
// 创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
// 模仿vue的操作(真正的Vue中要复杂得多~)
let vm = {}
vm._data = data = obs
function Observer(obj){
// 获取data中所有属性名
const keys = Object.keys(obj)
// 遍历每个属性,给每个属性添加get,set
keys.forEach(k => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
obj[k] = val
}
})
})
}
console控制台图示
补充 - Vue中对对象、数组添加属性
对象
上面说到Vue中的data数据在使用之前其实被做了一次处理(即添加了get()和set()方法,当然Vue中的处理还是比较复杂的,比如对象做了深度处理,这里只做了简单示例),这样才能保证数据更新后页面及时同步渲染
但是在写Vue项目时,如果需要给data中的对象添加一个属性,例如:
const vm = new Vue({
el: '#app',
data: {
person: {
name: 'zhangsan',
sex: 'male'
}
},
mounted() {
this.person.age = 18
}
})
此时若查看person可以发现age属性并没有被添加get()和set()方法,也就是说age属性的改变并不能使页面及时更新,如下图:
所以Vue官方给出了Vue.set()方法(Vue实例是vm.$set()),用于给对象或者数组添加响应式属性值,通俗来说也就是给新加的属性也有对应的get()和set()方法。
const vm = new Vue({
el: '#app',
data: {
person: {
name: 'zhangsan',
sex: 'male'
}
},
mounted() {
// this.person.age = 18
this.$set(this.person, 'age', 18)
}
})
此时的age属性已经被添加了get()和set()方法,如下图:
数组
对于数组来说,Vue对数组的操作方法做了包裹,这些方法包含:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
详情查看数组变更方法
也就是说修改数组属性不要指定index直接操作,要使用上述方法修改,或者用vm.$set()