本文是要實作對象使用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);
//并不能監測數組屬性的改變,需要重寫數組方法,下一章介紹