1. vue的数据劫持/响应式原理:是基于Object.defineProperty实现的(IE8以下不支持Object.defineProperty),监听data里面的数据,如果data里面的数据改变,就触发视图改变(重新渲染)。
let options={
data:{
name:"Ace",
age:18
},
render(){
}
}
class AVue{
constructor(options){
this._data=options.data; //即{name:"Ace",age:18}
this.watchDataChange(this._data,options.render);
}
watchDataChange(data,render){
let _this=this;
Object.keys(data).forEach((key)=>{
_this.dataChange(data,key,render);
_this.proxyDataChange(key,render);
})
}
proxyDataChange(key,render){ //代理 ,原本是options.data.name取值修改值,代理之后 可以options.name取值修改值
let _this=this;
Object.defineProperty(_this,key,{ //即this上设置key属性,比如 options.name,options.age
configrable:true,
enumerable:true,
get:()=>{
return _this._data[key]
},
set:(newVal)=>{
if(newVal !==val){
_this._data[key]=newVal;
render();
}
}
})
}
dataChange(obj,key,render){
Object.defineProperty(obj,key,{ //options.data.name,options.data.age
configrable:true, //是否可删除该属性
enumerable:true, //是否可遍历该数据
get:()=>{
return obj[key]
},
set:newVal=>{
if(newVal !==val){
obj[key]=newVal;
render();
}
}
})
}
}
//实例化AVue
let app = new AVue({
el: '#app',
data: {
text: 'text',
text2: 'text2'
},
render(){
console.log("render");
}
})
注意:以上简化存在的一个问题:当data里面的数据,如job:'IT',在实际模板中并没有被用到,然而当job的数据被修改(this.job= 'CEO')的时候,同样会触发job的setter导致重新执行渲染,这存在性能问题。vue通过依赖收集使得只有数据在实际模块中被调用用到时才会重新渲染。
2.Object.defineProperty(obj,key,des)属性:作用是直接在一个对象上定义一个新属性,或者修改/获取一个已经存在的属性。
Object.defineProperty(obj,key,{
configurable:bool, //属性的值是否可以被重写
enumerable:bool, //属性的值是否可以被枚举
value:any, // 任意值
writable:bool, //是否可以编辑
get:()=>{return obj[key]}, //获得
set:(newVal)=>{obj[key]=newVal} //设置
});