Object.defineProperty的基本使用

如何实现一个对象属性监听?

var data = {
    a: 1,
    b: {
        b1: 2
    },
}

一个简单的对象,如何在改变它的某个属性值是监听得到当前属性,例如:

对某个元素进行操作时打印set xxx = xxx

data.a = 'a'  //set a = a

data.b.b1 = 'b' // set b1 = b

Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法: 

Object.defineProperty(obj, prop, descriptor)


参数:

obj
要定义属性的对象。

prop
要定义或修改的属性的名称或 Symbol 。

descriptor
要定义或修改的属性描述符。

返回值
被传递给函数的对象。

代码示例

var data = {
    a: 1
}

Object.defineProperty(data, 'a', {
    get: () => {
        return value
    },
    set: (v) => {
        value = v
        console.log(`set a = ${v}`);
    }
})

data.a = 'a'

此时运行后显示

如何监听多层对象?

初始化一个复杂对象:

var data = {
    a: 1,
    b: {
        b1: 2,
        b2: {
            b31: 4,
            b32: 5
        }
    },
    c: 3
}

写一个方法进行遍历:


function watcher(obj) {
    if (typeof obj !== 'object') return
    for (const key in obj) {
        observer(obj, key)
    }
}

将监听写到一个observer方法里,并判断该下面的方法是否是对象,是的话递归调用监听方法,可以监听某对象下的属性

const observer = function (obj, prop) {
    if (obj && typeof (obj[prop]) === 'object') {
        watcher(obj[prop])
    }

    var value = obj[prop]
    Object.defineProperty(obj, prop, {
        get: () => {
            return value
        },
        set: (v) => {
            value = v
            console.log(`set ${prop} = ${v}`);
        }
    })
}

运行结果如图所示:

完整代码

const observer = function (obj, prop) {
    if (obj && typeof (obj[prop]) === 'object') {
        watcher(obj[prop])
    }

    var value = obj[prop]
    Object.defineProperty(obj, prop, {
        enumerable: true,
        configurable: true,
        get: () => {
            return value
        },
        set: (v) => {
            if (v !== value) {
                value = v
                watcher(v)
                console.log(`set ${prop} = ${v}`);
            }
        }
    })
}

var data = {
    a: 1,
    b: {
        b1: 2,
        b2: {
            b31: 4,
            b32: 5
        }
    },
    c: 3
}

function watcher(obj) {
    if (typeof obj !== 'object') return
    for (const key in obj) {
        observer(obj, key)
    }
}

watcher(data)

data.a = 'a'  //set c = a

data.b.b1 = 'b'// set b1 = b

data.b.b2.b31 = 'b3'// set b3 = b3

console.log('data', data);