Skip to content

Object.defineProperty

在一个对象上定义新的属性或修改现有属性,并返回该对象

  • obj:要定义属性的目标对象
  • prop:要定义或修改的属性的名称
  • descriptor:属性的描述符对象
    • value:属性值
    • writable:属性值是否可修改
    • enumerable:是否可枚举
    • configurable:是否可被删除
    • get:该属性的 getter 函数,用于返回属性的值。如果定义了 get,则该属性会变成一个访问器属
    • set:该属性的 setter 函数,用于设置属性的值。如果定义了 set,则该属性会变成一个访问器属性

定义单一属性

js
function defineProperty() {
    var _obj = {}
    // 定义单一属性
    Object.defineProperty(_obj, 'a', {
        value: 1
    })
    return _obj
}
var obj = defineProperty()
console.log('🚀 ~ obj:', obj)

定义多属性

js
function defineProperty() {
    var _obj = {}
    // 定义多属性
    Object.defineProperties(_obj, {
        a: {
            value: 1
        },
        b: {
            value: 2
        },
        c: {
            value: 3
        }
    })

    return _obj
}
var obj = defineProperty()
console.log('🚀 ~ obj:', obj)

此时obj不可修改、不可枚举、不可删除,因为没有配置descriptor

可进行删除、修改、枚举的配置

js
function defineProperty() {
    var _obj = {}
    // 定义多属性
    Object.defineProperties(_obj, {
        a: {
            value: 1,
            writable: true,
            enumerable: true,
            configurable: true
        },
        b: {
            value: 2
        },
        c: {
            value: 3
        }
    })

    return _obj
}
var obj = defineProperty()
obj.a = 5
delete obj.a
console.log('🚀 ~ obj:', obj)

get与set

js
const obj = {}
let _name = 'Alice'

Object.defineProperty(obj, 'name', {
    get: function () {
        return _name
    },
    set: function (newName) {
        _name = newName
    },
    enumerable: true,
    configurable: true
})

console.log(obj.name) // "Alice"
obj.name = 'Bob'
console.log(obj.name) // "Bob"

数据劫持:阻拦正常的输出和输入,对descriptor进行一系列配置,按照get和set里的逻辑进行数据操作的逻辑,这就叫做数据劫持

尝试对数组进行数据劫持

js
function DataArr() {
    var _val = null,
        _arr = []
    Object.defineProperty(this, 'val', {
        get: function () {
            return _val
        },
        set: function (newVal) {
            _val = newVal
            _arr.push({ val: _val })
            console.log(`new value${_val}`)
        }
    })
    this.getArr = function () {
        return _arr
    }
}
var dataArr = new DataArr()
dataArr.val = 123
dataArr.val = 234
console.log('🚀 ~ dataArr:', dataArr)

Proxy

ES6的一个构造函数,用于创建一个对象的代理,从而实现基本操作的拦截和自定义

  • target:原始对象
  • handler:定义拦截行为的对象,包含多个陷阱方法
    • get(target, prop, receiver):拦截对象属性的读取。
    • set(target, prop, value, receiver):拦截对象属性的设置。
    • has(target, prop):拦截 in 操作符。
    • deleteProperty(target, prop):拦截删除属性的操作。
    • apply(target, thisArg, argumentsList):拦截函数调用。
    • construct(target, argumentsList, newTarget):拦截构造函数的调用。

Object.defineProperty与Proxy主要区别

defineProperty是直接处理obj,并且在set和get去拦截

proxy是处理了obj后返回了一个代理对象

简单用法

js
var target = {
    a: 1,
    b: 2
}
let proxy = new Proxy(target, {
    get(target, propKey) {
        console.log(`tar:${target},propKey:${propKey},value:${target[propKey]}`)
        return target[propKey]
    },
    set(target, propKey, value) {
        target[propKey] = value
    }
})
console.log('🚀 ~ proxy:', proxy.a)