09-属性描述符Object.getOwnPropertyDescriptor(),原始数据不可重写

文章讲述了如何使用JavaScript的Object.defineProperty方法来创建只读属性,以及通过getter和setter确保数据安全。通过设置属性描述符的writable、enumerable和configurable,防止原始数据被修改。此外,还介绍了利用内部变量和验证函数限制数值类型的属性,并使用Object.freeze()来冻结对象,防止新增或修改属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

把原始数据作为属性值传入新对象中,发生原始数据修改丢失的问题怎么办?

  • 应该使用Object.defineProperty()设置该属性
  • 用Object.defineProperty()设置的属性,默认writable、enumerable、configurable均为false
  • 并且自定义提醒该属性设置了不可重写
let obj = {
	a: 1
};

for (const key in obj) {
	console.log(key);
}

let keys = Object.keys(obj);
console.log(keys);

let desc = Object.getOwnPropertyDescriptor(obj, 'a');
console.log(desc);

描述a:

值为1,可重写,可遍历

得到属性描述符

Object.getOwnPropertyDescriptor(obj, 'a');

重设属性描述符

Object.defineProperty(obj, 'a', { })

value: 23, //内容

writable: false, //不可重写

enumerable: false, //不可遍历

configurable: false //属性描述符本身可不可以重复修改

// 重新设置属性描述符
Object.defineProperty(obj, 'a', {
	value: 23,
	writable: false, //不可重写
	enumerable: false, //不可遍历
	configurable: false //属性描述符本身可不可以重复修改
}) 
/* 以下是无效的修改,因为上面的configurable: false */
Object.defineProperty(obj, 'a', {
	value: 23,
	writable: false, //不可重写
}) 
obj.a = 10;
console.log(obj.a);

getter读取器

读取属性值

setter设置器

属性值重新赋值,有一个形参

合称访问器

设置了get和set函数后,将来读取这个属性时,他不会去内存中找,而是运行get函数

get函数里是什么,属性值输出就是什么

Object.defineProperty()定义的属性,属性值被修改时实际上在执行什么代码?

let obj = {};

Object.defineProperty(obj, 'a', {
	get: function () {
		console.log('hello');
		return 2
	},
	set: function (val) {
		console.log('你好');
	}
})
// obj.a = 10;
obj.a = 3 - 2; // set(3-2)
console.log(obj.a); // console.log(get())

输出结果:你好  hello  2

这里定义了一个空对象,用 defineProperty 定义了一个属性 a

obj.a = 3 - 2; 这句话意思是在重新赋值,所以属性值改变的时候,是调用set函数

console.log(obj.a); 得到属性 a 的值,其实就是读取属性值,调用get函数

利用set函数限定原始数据的属性不可重写

let obj = {
	pic: './assets/g1.png',
	title: '椰云拿铁',
	desc: `1人份【年度重磅,一口吞云】`,
	choose: 0,
	sellNumber: 200,
	favorRate: 95,
	price: 32,
}

class UIGoods {
	constructor(g) {
		// this.data = g;
		Object.defineProperty(this, 'data', {
			get: function () {
				return g;
			},
			set: function () {
				throw new Error('data属性时是只读的,不能赋值和修改!')
			},
			configurable: false,
		})
	}
}

const g = new UIGoods(obj);
g.data = 'ab';
console.log(g.data);

利用set函数限定数值类型的属性,设置中间变量,判断它的值和类型

let internalChooseValue = 0;
Object.defineProperty(this, 'choose', {
	get: function () {
		return internalChooseValue;
	},
	set: function (val) {
		if (typeof val !== 'number') {
			throw new Error(`choose属性必须是数字!`);
		}
		let temp = parseInt(val);
		if (temp !== val) {
			throw new Error(`choose属性必须是整数!`);
		}
		if(val < 0) {
			throw new Error(`choose属性必须大于等于0!`);
		}
		internalChooseValue = val;
	},
	configurable: false
})

利用get函数限定总价

Object.defineProperty(this, 'totalPrice', {
	get: function () {
		return this.choose * this.data.price;
	}
})

er6语法糖简写,和constructor同级

get totalPrice () {
	return this.choose * this.data.price;
}

利用get函数限定设置isChoose

get isChoose () {
	return this.choose > 0;
}

Object.freeze()冻结原始数据的克隆版,让它的属性值也不能修改

尽量不要直接修改原始数据

 避免新加属性进去 Object.freeze(this);

 在最后冻结自己,可以防止新加属性改变数据,但是其他普通属性就不能改了

 要使其他普通属性可修改,将freeze换成seal

这样使其他普通属性可修改,原始数据不可修改

限制不能在原型上添加属性

<think>好的,我现在需要解决用户的问题:如何通过Object.getOwnPropertyDescriptor结合Object.defineProperty动态更新属性描述符的值。首先,我需要回顾这两个方法的作用和用法。 用户提到了Object.defineProperty,这个方法用于定义或修改对象的属性描述符。而Object.getOwnPropertyDescriptor则是用来获取对象某个属性描述符。动态更新可能需要先获取当前的描述符,然后修改其中的某些特性,再重新应用回去。 接下来,我需要确保步骤正确。首先,使用Object.getOwnPropertyDescriptor获取当前描述符,这可能包括value、writable、enumerable、configurable等属性。然后,检查这个描述符是否存在,如果属性不存在,返回undefined。接着,修改需要变更的部分,比如value或者writable的值。最后,使用Object.defineProperty将修改后的描述符应用到对象上。 需要注意的是,如果原属性的configurable为false,那么无法重新配置该属性,会抛出错误。所以必须确保属性是可配置的。例如,如果原属性的writable为false,且没有设置configurable为true,那么不能修改value,除非writable被改为true。这可能是一个容易出错的地方,需要提醒用户注意。 另外,用户可能希望动态更新属性,比如根据条件改变getter或setter函数,或者调整enumerable的值。这时候,获取描述符后,替换对应的函数或值,再重新定义即可。例如,修改getter函数后,再次调用Object.defineProperty应用新的描述符。 我应该举例说明,比如先创建一个对象obj,有一个属性a,然后获取其描述符,修改value或writable,再重新定义。同时,处理访问器属性的情况,比如修改getter。另外,需要强调configurable的重要性,如果不可配置,则无法修改。 可能还需要提到错误处理,比如在尝试修改不可配置属性时捕获TypeError。这样用户在实际应用中能避免程序崩溃。 最后,总结步骤:获取描述符、修改描述符属性、重新定义属性。同时,注意事项包括configurable的设置和潜在的错误处理。确保示例代码覆盖数据属性和访问器属性两种情况,以全面展示方法的应用。</think>### 通过 `Object.defineProperty` 结合 `Object.getOwnPropertyDescriptor` 动态更新属性描述符的值 #### 步骤说明 1. **获取属性描述符** 使用 `Object.getOwnPropertyDescriptor(obj, prop)` 获取目标属性描述符对象,包含 `value`、`writable`、`enumerable`、`configurable` 等特性[^2][^3]。 2. **修改描述符属性** 直接修改获取到的描述符对象中的特性值(例如 `value`、`writable`),或替换 `get`/`set` 方法(若为访问器属性)。 3. **重新定义属性** 通过 `Object.defineProperty(obj, prop, modifiedDescriptor)` 将修改后的描述符应用到对象属性上[^4]。 #### 代码示例 ```javascript // 示例对象 const obj = {}; // 初始定义属性 Object.defineProperty(obj, 'a', { value: 1, writable: false, enumerable: true, configurable: true // 必须为 true 才能修改描述符 }); // 1. 获取属性描述符 const descriptor = Object.getOwnPropertyDescriptor(obj, 'a'); console.log(descriptor.value); // 输出: 1 // 2. 修改描述符属性 descriptor.value = 2; descriptor.writable = true; // 3. 重新定义属性 Object.defineProperty(obj, 'a', descriptor); // 验证修改结果 console.log(obj.a); // 输出: 2 obj.a = 3; console.log(obj.a); // 输出: 3 (writable 已生效) ``` #### 动态更新访问器属性 ```javascript const obj2 = {}; // 初始定义访问器属性 let internalValue = 10; Object.defineProperty(obj2, 'b', { get() { return internalValue; }, set(newVal) { internalValue = newVal; }, configurable: true }); // 获取并修改描述符 const descriptor2 = Object.getOwnPropertyDescriptor(obj2, 'b'); descriptor2.get = function() { return internalValue * 2; }; // 修改 getter // 重新定义属性 Object.defineProperty(obj2, 'b', descriptor2); console.log(obj2.b); // 输出: 20 (原值为10,修改后返回双倍) ``` #### 注意事项 1. **`configurable` 必须为 `true`** 若原属性的 `configurable` 为 `false`,则无法修改除 `writable` 以外的特性,且 `writable` 只能从 `true` 改为 `false`[^5]。 2. **错误处理** 若尝试修改不可配置属性,会抛出 `TypeError`,建议用 `try...catch` 包裹代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值