定义: 数据劫持,指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。
简单地说,就是当我们 触发函数的时候 动一些手脚做点我们自己想做的事情,也就是所谓的 "劫持"操作
Object.defineProperty(obj,prop,descriptor)
参数:
可供定义的特性列表:
在Vue中其实就是通过Object.defineProperty
来劫持对象属性的setter
和getter
操作,并“种下”一个监听器,当数据发生变化的时候发出通知,如下:
var data = {
name:'test'}
Object.keys(data).forEach(function(key){
Object.defineProperty(data,key,{
enumerable:true,
configurable:true,
get:function(){
console.log('get');
},
set:function(){
console.log('监听到数据发生了变化');
}
})
});
data.name //控制台会打印出 “get”
data.name = 'hxx' //控制台会打印出 "监听到数据发生了变化"
参考 前端vue面试题详细解答
上面的这个例子可以看出,我们完全可以控制对象属性的设置和读取。在Vue中,在很多地方都非常巧妙的运用了Object.defineProperty
这个方法,具体用在哪里并且它又解决了哪些问题,下面就简单的说一下:
它通过observe每个对象的属性,添加到订阅器dep中,当数据发生变化的时候发出一个notice。 相关源代码如下:(作者采用的是ES6+flow写的,代码在src/core/observer/index.js模块里面)
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: Function
) {
const dep = new Dep()//创建订阅对象
const property = Object.getOwnPropertyDe述 //属性的描述特性里面如果configurable为false则属性的任何修改将无效
if (property && property.configurable === false) {
return }scriptor(obj, key)//获取obj对象的key属性的描
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
let childOb = observe(val)//创建一个观察者对象
Object.defineProperty(obj, key, {
enumerable: true,//可枚举
configurable: true,//可修改
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val//先调用默认的get方法取值 //这里就劫持了get方法,也是作者一个巧妙设计,在创建watcher实例的时候,通过调用对象的get方法往订阅器dep上添加这个创建的watcher实例 if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
}
if (Array.isArray(value