????????該方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回此對象。應(yīng)當(dāng)直接在object構(gòu)造器上調(diào)用此方法,而不是在任意一個object類型的實例上調(diào)用。
Object.defineProperty(obj, prop, descriptor)
參數(shù):
obj:要定義屬性的對象
prop:要定義或修改的屬性名稱或symbol
descriptor:要定義或修改的屬性描述符
????????對象里目前存在的屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符。數(shù)據(jù)描述符是一個具有值的屬性,該值可以是可寫的,也可以是不可寫的。存取描述符是由getter函數(shù)和setter函數(shù)所描述的屬性。一個描述符只能是這兩者其中之一,不能同時是兩者。
| 左對齊 | 右對齊 | 居中對齊 |
|---|---|---|
| 單元格 | 單元格 | 單元格 |
| 單元格 | 單元格 | 單元格 |
| 屬性名 | configurable | enumerable | value | writable | get | Set |
|---|---|---|---|---|---|---|
| 作用 | 是否可配置對象(刪除屬性) | 是否可枚舉 | 是否可以修改對象 | 獲取obj.key | 將修改的值重新賦值 | |
| 默認(rèn)值 | false | false(也就是object.defineproperty定義的屬性默認(rèn)是不能被遍歷的) | undefined | false | undefined | undefined |
| 數(shù)據(jù)描述符 | 可有 | 可有 | 可有 | 可有 | 不可有 | 不可有 |
| 存取描述符 | 可有 | 可有 | 不可有 | 不可有 | 可有 | 可有 |
Object.defineProperty(obj, key, {
// 1.value
enumerable: true, // 4.可以枚舉
configurable: true, // 2.可以配置對象,刪除屬性
// writable: true // 3.可以修改對象
// get,set設(shè)置時不能設(shè)置writable和value,它們代替了 二者是互斥的 可以去看數(shù)據(jù)描述符和存取描述符
// 5.獲取obj.key的時候就會調(diào)用get方法
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
// 6.將修改的值重新賦值
// 當(dāng)我們更新data的時候,會觸發(fā)set方法,執(zhí)行dep.notify()方法
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})