属性描述符

大约 2 分钟

属性描述符

获取和设置属性描述符

var obj = {
    a: 1,
    b: 2
}

// 获取属性描述符
const desc = Object.getOwnPropertyDescriptor(obj, 'a') // 这里获取 obj 的 a 属性的属性描述符
console.log(desc) // {value: 1, writable: true, enumerable: true, configurable: true}
/*
	value: 属性的值
	writable: 属性是否可以重写
	enumerable: 属性是否可以遍历得到
	configurable: 属性描述符本身是否可以修改
*/

// 设置属性描述符
Object.defineProperty(obj, 'a', {
    value: 10,
    writable: false,
    enumerable: false,
    configurable: false
})
obj.a = 20 // 不生效,因为上面设置了这个属性不能被重写
for (var key in obj) {
    console.log(key) // 这里不会输出 a ,因为设置了这个属性无法通过遍历得到
}

Object.defineProperty(obj, 'a', {
    writable: true // 不生效,因为上面设置了属性描述符本身无法被修改了
})

读取器(getter) 和设置器(setter)

属性描述符中有另外两个配置:get() 和 set() ,这两个配置就是读取器和设置器,他们的作用分别是读取属性的值和设置属性的值。

var obj = {}

var interanlValue = undefined
Object.defineProperty(obj, 'a', {
    get: function() {
        return interanlValue
    },
    set: function(val) {
        interanlValue = val
    }
})

console.log(obj.a) // undefined
obj.a = 1
console.log(obj.a) // 1

使用 getter 和 setter 编写一个更加牢固的构造函数:

var obj = {
    a: undefined,
    b: undefined
}

class NewObj {
    constructor(obj) {
        Object.defineProperty(this, 'data', {
            get: function() {
                return obj
            },
            set: function() {
                throw new Error('data 属性是只读的,无法进行修改')
            },
            configurable: false,
        })
        let interanlText = undefined // text 属性赋值时的暂存变量
        Object.defineProperty(this, 'text', {
            get: function() {
                return interanlText
            },
            set: function(val) {
                // 这里也可以写一些限定条件(if判断)来限制该属性只能赋值为什么
                interanlText = val
            },
            configurable: false,
        })
    }
}

var obj1 = new NewObj(obj)
console.log('obj1.data', obj1.data) // obj1.data { a: undefined, b: undefined }
console.log('obj1.text', obj1.text) // obj1.text undefined
obj1.text = 123
console.log('obj1.text', obj1.text) // obj1.text 123
obj1.data = 123 // Error: data 属性是只读的,无法进行修改

/*
	上面这种写法虽然比较牢固,但是还是有其他的问题,如:
		1、通过修改原始数据来修改:obj1.data.a = 123
			防止的方法:使用 Object.freeze(obj) 来冻结数据,但是为了防止以后原始数据可能会有修改的需求,因此我们应该先将原始数据克隆,然后冻结克隆后的数据,如:`obj = { ...obj }; Object.freeze(obj)` 
		2、可以给 obj1 添加属性:如直接使用 obj1.newData = 'hhh' 
			防止的方法:在所有操作完成后,对自身进行冻结,Object.freeze(this)
		3、在第二个问题的操作后,我们不光不能给 obj1 添加属性了,当 obj1 中有其他的属性时,其他属性也无法修改了
			防止的方法:为了防止其他属性以后有修改的可能,我们可以将 Object.freeze(this) 替换为 Object.seal(this),对自身进行密封
		4、通过原型修改数据:NewObj.prototype.haha = 'haha'
			防止的方法:对原型进行冻结,Object.freeze(NewObj.prototype)
*/
上次编辑于: