使用defineProperty实现一个简单的观察者

38 阅读1分钟

Object.defineProperty()使用方法

Object.defineProperty()  静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象,例如:

属性设置不可修改

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx', // 值
    writable: false // 是否可以被修改
})
myObj.name = '李思思'
console.log(myObj.name) // wangtx

属性设置可修改

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx', // 值
    writable: true // 是否可以被修改
})
myObj.name = '李思思'
console.log(myObj.name) // 李思思

使用get/set访问属性

const myObj = {}
const ageVal = 100
Object.defineProperty(myObj, 'age', {
    get(){
        return ageVal + 1
    },
    set(age){ ageVal = age }
})
console.log(myObj.age) // 101

不能被枚举

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx',
    writable: false,
    enumerable: false // 不可被枚举
})
console.log(Object.keys(myObj)) // []
for(i in myObj) { console.log(i) } //

可以被枚举

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx',
    writable: false,
    enumerable: true // 可以被枚举
})
console.log(Object.keys(myObj)) // ['name']
for(i in myObj) { console.log(i) } // name

属性不可被删除

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx',
    writable: false,
    enumerable: true,
    configurable: false // 不可被删除
})
delete myObj.name
console.log(myObj) // {name: 'wangtx'}

属性可以被删除

const myObj = {}
Object.defineProperty(myObj, 'name', {
    value: 'wangtx',
    writable: false,
    enumerable: true,
    configurable: true // 可以被删除
})
delete myObj.name
console.log(myObj) // {}

实现继承

function MyClass() {}
let value;
Object.defineProperty(MyClass.prototype, "x", {
  get() {
    return value;
  },
  set(x) {
    value = x;
  },
});

const a = new MyClass();
const b = new MyClass();
a.x = 1;
console.log(b.x); // 1

属性直接定义与手动定义的区别

const myObj = {};
myObj.a = 1;
// 等价于:
Object.defineProperty(myObj, "a", {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true,
});

// 另一种情况
Object.defineProperty(myObj, "a", { value: 1 });
// 等价于:
Object.defineProperty(myObj, "a", {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false,
});

实现一个简单的observe观察

function change() {
    console.log('更新了!')
}
// 属性定义
function defineReactive (obj, key, val) {
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
            return val;
        },
        set: function reactiveSetter (newVal) {
            if (newVal === val) return;
            val = newValue
            change(newVal);
        }
    });
}
// 定义观察者
function observer (value) {
    if (!value || (typeof value !== 'object')) return
    Object.keys(value).forEach((key) => {
        defineReactive(value, key, value[key]);
    });
}
// 定义一个Vue类
class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data);
    }
}
// 实例化类
let o = new Vue({
    data: {
        words: "I am test."
    }
});
o._data.words = "hello,world.";