本文是要实现对象使用Object.defineProperty重写对象,例
//例把下面对象obj
let obj={a:1};
//修改成以下写法
let aValue=1;
Object.defineProperty(obj,a,{
get(){
return aValue;
},
set(newValue){
if(aValue===newValue) return;
aValue=newValue;
}
})
这样在对对象属性进行获取、修改时,都能在get、set中监测到对象属性变化,但不能对对象属性值为数组进行监测,需要重写数组方法,下一篇
首先介绍Object.defineProperty:
作用是给对象的属性设置get、set、value、writable(可重写)、configurable(可配置、删除)、enumerable(可遍历)等
其中writable不能和get、set一起出现,get、set不能和value一块出现
Object.defineProperty(obj,key,{
value,//属性值
writable,//boolean
configurable,//boolean
enumerable,//boolean
get(){},//不能和writable、value一块配置
set(newValue){}//不能和writable、value一块配置
})
******************************正文开始********************************
在使用vue时
//在这里只对vue的data进行处理
let vm = new Vue({
data:function(){
return {
a:1,
b:{c:2}
}
}
})
可以把以上改成
let options={
data:function(){
return {
a:1,
b:{c:2}
}
}
}
let vm = new Vue(options)
模仿以上,创建一个函数命名为Vue,
function Vue(options){
}
问题:Vue如何将options里的data转成Object.defineProperty的写法
解剖问题:
1、在new Vue()时即完成了到Object.defineProperty的转换
解决:在new Vue()时执行了一个方法,命名为_init
function Vue(options){
this._init(options);
}
Vue.prototype._init=function(options){
console.log("new的时候执行了_init")
}
解析 new Vue()会将所有的属性实例化,所以this_init()也会被执行,执行的时候会在对象的原型链中查找同名方法,所以会找到Vue.prototype._init方法,我们可以在_init中对options进行处理
开始正题
1、封装Object.defineProperty
function defineReactive(obj,key,value){
Object.defineProperty(obj,key,{
get(){
return value;
},
set(newValue){
if(newValue===value) return;
value=newValue;
},
configurable:true,
enumerable:true
})
}
2、封装判读当前变量是不是需要被观察
function observe(data){
if(typeof data!=="object"||data===null){return}
walk(data);
}
3、遍历对象并设置Object.defineProperty
function walk(data){
let keys=Object.keys(data);
for(let i=0;i<keys.length;i++){
defineReactive(data,keys[i],data[keys[i]])
}
}
以上会有一个问题,如果是{a:1}这种则没问题,如果{a:1,b:{c:2}},则不能遍历到底层,所以需要在设置get前对设置的值进行判断当前值需不需要被观察,如果需要被观察,先观察,不需要直接给当前属性赋值
function defineReactive(obj,key,value){
observe(value);//判断当前值需不需要被观察,需要观察,先观察再进行下面的处理
Object.defineProperty(obj,key,{
get(){
return value;
},
set(newValue){
if(newValue===value) return;
value=newValue;
},
configurable:true,
enumerable:true
})
}
function defineReactive(obj,key,value){
observe(value);//判断当前值需不需要被观察,需要观察,先观察再进行下面的处理
Object.defineProperty(obj,key,{
get(){
return value;
},
set(newValue){
if(newValue===value) return;
value=newValue;
observe(newValue);
},
configurable:true,
enumerable:true
})
}
obj ={
a:[2,3]
}
obj.a.push(4);
//并不能监测数组属性的改变,需要重写数组方法,下一章介绍