js Object.defineProperty() 描述符的特性功能详解

Object.defineProperty(obj, prop, descriptor)
在对象 obj 上新建或修改一个属性 prop, 并返回新 obj

obj: 要定义属性的对象
prop: 要定义或修改的属性的名称或 Symbol
descriptor: 要定义或修改的属性的描述符
descriptor.configurable: 对象的属性的描述符的特性

属性的 descriptor (描述符)分两种[数据描述符, 存取描述符(访问描述符)], descriptor 只能是其中一种;
descriptor 为数据描述符时, 该属性称为数据属性;为存取描述符时, 该属性称为存取属性;
数据属性可以用 [对象.属性 = 值] 方式定义;
存取属性只能通过 Object.defineProperty() 来定义;
descriptor 的属性称为特性, 共[configurable, enumerable, value, writable, get, set]6个, 但这6个不可以共存;

// [对象.属性 = 值] 方式的 数据描述符 的特性的默认值
descriptor = {
    
    
	configurable: true,
	enumerable: true,
	value: undefined,
	writable: true
}
// defineProperty 方式的 数据描述符 的特性的默认值
descriptor = {
    
    
	configurable: false,
	enumerable: false,
	value: undefined,
	writable: false
}
// 存取描述符 的特性的默认值
descriptor = {
    
    
	configurable: false,
	enumerable: false,
	get: undefined,
	set: undefined
}

特性使用条件:

  • configurable, enumerable 是公共特性
  • value, writable 属于数据描述符的特性
  • get, set 属于存取描述符的特性
  • descriptor 有[value, writable] 时, 即为数据描述符;有[get, set] 时, 即为存取描述符
  • descriptor 为空时, 默认为数据描述符
  • [value, writable] 与 [get, set] 不能同时存于一个 descriptor, 否则异常

公用可选键值(特性):

configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。


enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false。

数据描述符还具有以下可选键值(特性):

value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined。


writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
默认为 false。

存取描述符还具有以下可选键值(特性):

get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为 undefined。


set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认为 undefined。

详解见下面demo

<html>

<head>
	<title>js Object.defineProperty() 描述符的特性功能详解</title>
</head>

<body>

	<script type="text/javascript">
		"use strict"

		function section1() {
    
    
			let _obj = {
    
    }
			let descriptor = Object.create(null) // 相当于没有 __proto__ 的 {}
			descriptor.value = 1

			// 默认 false, 写不写都一样
			// descriptor.writable = false
			// descriptor.enumerable = false
			// descriptor.configurable = false

			Object.defineProperty(_obj, "val", descriptor);

			console.log("_obj: 对象")
			console.log("\"val\": 对象的属性名")
			console.log("descriptor: 对象的属性的描述符")
			console.log("descriptor.value: 对象的属性的描述符的特性")

		}

		function section2() {
    
    
			let _obj = {
    
    }

			Object.defineProperty(_obj, "val", {
    
    
				value: "val 未修改",
				// writable: false,
				// enumerable: false,
				configurable: false
			});
			Object.defineProperty(_obj, "val2", {
    
    
				value: "val2 未修改",
				// writable: false,
				// enumerable: false,
				configurable: true
			});
			try {
    
    
				Object.defineProperty(_obj, "val", {
    
    
					value: "val 修改",
				});
			} catch (error) {
    
    
				console.warn("[val] configurable: false, 该属性的描述符不可以修改")
			}

			Object.defineProperty(_obj, "val2", {
    
    
				value: "val2 修改",
			});

			try {
    
    
				delete _obj.val
			} catch (error) {
    
    
				console.warn("[val] configurable: false, 该属性不可以被 delete")
			}

			console.log(_obj.val) // val 未修改
			console.log(_obj.val2) // val2 修改

			delete _obj.val2

			console.log(_obj.val2) // undefined
			// val2 被 delete 了

			// 描述符不可以修改指, 除了 writable: true 改 false, [value, writable, configurable, enumerable, get, set] 都不可以修改
			// 前后值相同不算"修改"
		}

		function section3() {
    
    
			let _obj = {
    
    }

			Object.defineProperty(_obj, "val", {
    
    
				value: "val 未修改",
				writable: false,
				// enumerable: false,
				// configurable: false,
			});

			try {
    
    
				_obj.val = "val 修改"
			} catch (error) {
    
    
				console.warn("[val] writable: false, 该属性不能被重新赋值")
			}

			console.log(_obj.val) // val 未修改

		}

		function section4() {
    
    
			let _obj = {
    
    }

			Object.defineProperty(_obj, "val", {
    
    
				value: "val enumerable: false",
				// writable: false,
				enumerable: false,
				// configurable: false,
			});
			Object.defineProperty(_obj, "val2", {
    
    
				value: "val2 enumerable: true",
				// writable: false,
				enumerable: true,
				// configurable: false,
			});

			for (var i in _obj) {
    
    
				console.log(_obj[i]);
			}
			console.log(Object.keys(_obj)) // ["val2"]

			_obj.propertyIsEnumerable("val") // false
			_obj.propertyIsEnumerable("val2") // true

			console.log("[val] enumerable: false, 该属性不能被[for in], Objeck.keys() 等循环方法枚举")

		}

		function section5() {
    
    
			let _obj = {
    
    
				_val: null,
				_val2: null,
			}

			Object.defineProperty(_obj, "val", {
    
    
				get() {
    
    
					console.log("get")
					console.warn("在 get 中调用本属性, 会进入死循环")
					return this._val;
				},
				set(newValue) {
    
    
					console.log("set", newValue)
					this._val = newValue;
				},
				// enumerable: false,
				// configurable: false
			});

			// 赋值触发 set, 新值作为参数传入
			_obj.val = 1

			// 调用触发 get
			_obj.val

		}

		function section6() {
    
    
			let _obj = {
    
    }

			var _val = Object.defineProperty(_obj, "val", {
    
    });

			// 描述符为空时, 默认为数据描述符, { configurable: false, enumerable: false, value: undefined, writable: false }
			console.log(Object.getOwnPropertyDescriptor(_obj, "val"))

			Object.defineProperty(_obj, "val2", {
    
    
				get() {
    
     }
			});

			// get, set 默认为 undefined
			console.log(Object.getOwnPropertyDescriptor(_obj, "val2"))

			_obj.val3 = 3
			// 直接赋值的属性 [configurable, enumerable, writable] 为 true
			console.log(Object.getOwnPropertyDescriptor(_obj, "val3"))

			_obj.__proto__.val4 = 4
			// getOwnPropertyDescriptor 只能取自有属性, 也就是不能取原型链 __proto__ 上的属性
			console.log(Object.getOwnPropertyDescriptor(_obj, "val4"))

		}

		section1()
		section2()
		section3()
		section4()
		section5()
		section6()
	</script>
</body>

</html>



参考资料:
Object.defineProperty() - JavaScript | MDN

end

猜你喜欢

转载自blog.csdn.net/u013970232/article/details/109462642