【JavaScript】属性描述符

简介: 这些描述符可以通过 Object.defineProperty() 方法来定义或修改对象的属性特性。通过使用这些描述符,我们可以灵活地控制和定义对象的属性行为,例如限制某些属性只读、隐藏某些不需要枚举的属性等。总的来说,对象的属性描述符提供了对对象属性行为进行详细控制和定义的能力,包括可配置性、可枚举性、可写性、获取和设置方法等。这使得我们能够更好地管理和操作对象中的各个属性。

属性描述符的结构

在 JavaScript 中,对象的属性描述符用于描述和定义对象属性的特性。以下是常见的属性描述符及其作用:

  1. configurable:表示属性是否可以被删除或修改特性。如果设置为 false,则不能删除或修改该属性的特性。默认为 true。
  2. enumerable:表示属性是否可以通过 for...in 循环或 Object.keys() 方法进行枚举。如果设置为 false,则该属性不会出现在枚举中。默认为 true。
  3. value:表示属性的值。可以是任何有效的 JavaScript 值。
  4. writable:表示属性是否可以被赋值运算符修改。如果设置为 false,则该属性的值不能被修改。默认为 true。
  5. get:一个函数,用于获取属性的值。当访问该属性时,会调用该函数并返回其返回值。
  6. set:一个函数,用于设置属性的值。当给该属性赋值时,会调用该函数并传入新值作为参数。

注意这几个属性不是都可以一起设置。getset 以及 valuewritable 这两组是互斥的,设置了 getset 就不能设置 valuewritable,反之设置了 valuewritable 也就不可以设置 getset

使用示例

示例 1

下面示例演示了使用 value 读写属性值的基本用法。

varobj= {}  //定义空对象Object.defineProperty(obj, 'x', {value : 100})  //添加属性x,值为100console.log(Object.getOwnPropertyDescriptor(obj, 'x').value)  //返回100

示例 2

下面示例演示了使用 writable 属性禁止修改属性 x

varobj= {};
Object.defineProperty(obj, 'x', {
value : 1,  // 设置属性默认值为1writable : false// 禁止修改属性值});
obj.x=2;  //修改属性x的值console.log(obj.x)  // 1 说明修改失败

在正常模式下,如果 writablefalse,重写属性值不会报错,但是操作失败,而在严格模式下则会抛出异常。

示例 3

configurable 可以禁止修改属性描述符,当其值为 false 时,value、writable、enumerableconfigurable 禁止修改,同时禁止删除属性。

在下面示例中,当设置属性 x 禁止修改配置后,下面操作都是不允许的,其中 obj.x=5; 若操作失败,则后面 4 个操作方法都将抛出异常。

varobj=Object.defineProperty({}, 'x', {
configurable : false// 禁止配置})
obj.x=5// 试图修改其值console.log(obj.x);  // 修改失败,返回undefinedObject.defineProperty(obj, 'x', {value : 2})  // 抛出异常Object.defineProperty(obj, 'x', {writable: true})  // 抛出异常Object.defineProperty(obj, 'x', {enumerable: true})  // 抛出异常Object.defineProperty(obj, 'x', {configurable: true})  // 抛出异常

configurablefalse 时,如果把 writable=true 改为 false 是允许的。只要 writableconfigurable 有一个为 true,则 value 也允许修改。

getset 函数

除了使用点语法或中括号语法访问属性的 value 外,还可以使用访问器,包括 setget 两个函数。

其中,set( ) 函数可以设置 value 属性值,而 get( ) 函数可以读取 value 属性值。

借助访问器,可以为属性的 value 设计高级功能,如禁用部分特性、设计访问条件、利用内部变量或属性进行数据处理等。

示例 1

下面示例设计对象 objx 属性值必须为数字。为属性 x 定义了 getset 特性,obj.x 取值时,就会调用 get;赋值时,就会调用 set

varobj=Object.create(Object.prototype, {
_x : {  //数据属性value : 1,  //初始值writable : true    },
x : {  //访问器属性get : function () {  //getterreturnthis._x;  //返回_x属性值        },
set : function (value) {  //setterif (typeofvalue!="number"){
thrownewError('请输入数字');
            }
this._x=value;  //赋值        }
    }
});
console.log(obj.x);  //1obj.x="2";  //抛出异常

示例 2

JavaScript 也支持一种简写方法。针对示例 1,通过以下方式可以快速定义属性。

varobj= {
_x : 1,  // 定义 _x 属性getx() { returnthis._x },  //定义 x 属性的 gettersetx(value) {  //定义 x 属性的 setterif (typeofvalue!="number"){
thrownewError('请输入数字');
        }
this._x=value;  // 赋值    }
};
console.log(obj.x);  //1obj.x=2;
console.log(obj.x);  //2

取值函数 get( ) 不能接收参数,存值函数 set( ) 只能接收一个参数,用于设置属性的值。

操作属性描述符

属性描述符是一个内部对象,无法直接读写,可以通过下面几个函数进行操作。

  • Object.getOwnPropertyDescriptor( ):可以读出指定对象私有属性的属性描述符。
  • Object.defineProperty( ):通过定义属性描述符来定义或修改一个属性,然后返回修改后的描述符。
  • Object.defineProperties( ):可以同时定义多个属性描述符。
  • Object.getOwnPropertyNames( ):获取对象的所有私有属性。
  • Object.keys( ):获取对象的所有本地可枚举的属性。
  • propertyIsEnumerable( ):对象实例方法,直接调用,判断指定的属性是否可枚举。

示例 1

在下面示例中,定义 objx 属性允许配置特性,然后使用 Object.getOwnPropertyDescriptor( ) 函数获取对象 objx 属性的属性描述符。修改属性描述符的 set 函数,重设检测条件,允许非数值型数字赋值。

varobj=Object.create(Object.prototype, {
_x: {  //数据属性value: 1,  //初始值writable: true    },
x: {  //访问器属性configurable: true,  //允许修改配置get: function () {  //getterreturnthis._x;  //返回_x属性值        },
set: function (value) {
if (typeofvalue!="number") {
thrownewError('请输入数字');
            }
this._x=value;  //赋值        }
    }
});
vardes=Object.getOwnPropertyDescriptor(obj, "x");  //获取属性x的属性描述符des.set=function (value) {
//修改属性x的属性描述符set函数//允许非数值型的数字,也可以进行赋值if (typeofvalue!="number"&&isNaN(value*1)) {
thrownewError('请输入数字');
    }
this._x=value;
}
obj=Object.defineProperty(obj, "x", des);
console.log(obj.x);  //1obj.x="2";  //把一个给数值型数字赋值给属性xconsole.log(obj.x);  //2

示例 2

下面示例先定义一个扩展函数,使用它可以把一个对象包含的属性以及丰富的信息复制给另一个对象。

【实现代码】

functionextend (toObj, fromObj) {  //扩展对象for (varpropertyinfromObj) {  //遍历对象属性if (!fromObj.hasOwnProperty(property)) continue;  //过滤掉继承属性Object.defineProperty(  //复制完整的属性信息toObj,  //目标对象property,  //私有属性Object.getOwnPropertyDescriptor(fromObj, property)  //获取属性描述符        );
    }
returntoObj;  //返回目标对象}

【应用代码】

varobj= {};  //新建对象obj.x=1;  //定义对象属性extend(obj, { gety() { return2} })  //定义读取器对象console.log(obj.y);  //2

控制对象状态

JavaScript 提供了 3 种方法,用来精确控制一个对象的读写状态,防止对象被改变。

  • Object.preventExtensions:阻止为对象添加新的属性。
  • Object.seal:阻止为对象添加新的属性,同时也无法删除旧属性。等价于属性描述符的 configurable 属性设为 false。注意,该方法不影响修改某个属性的值。
  • Object.freeze:阻止为一个对象添加新属性、删除旧属性、修改属性值。

同时提供了 3 个对应的辅助检查函数,简单说明如下:

  • Object.isExtensible:检查一个对象是否允许添加新的属性。
  • Object.isSealed:检查一个对象是否使用了 Object.seal 方法。
  • Object.isFrozen:检查一个对象是否使用了 Object.freeze 方法。

示例

下面代码分别使用 Object.preventExtensions、Object.sealObject.freeze 函数控制对象的状态,然后再使用 Object.isExtensible、Object.isSealedObject.isFrozen 函数检测对象的状态。

varobj1= {};
console.log(Object.isExtensible(obj1));  //trueObject.preventExtensions(obj1);
console.log(Object.isExtensible(obj1));  //falsevarobj2= {};
console.log(Object.isSealed(obj2));  //trueObject.seal(obj2);
console.log(Object.isSealed(obj2));  //falsevarobj3= {};
console.log(Object.isFrozen(obj3));  //trueObject.freeze(obj3);
console.log(Object.isFrozen(obj3));  //false

总结

这些描述符可以通过 Object.defineProperty() 方法来定义或修改对象的属性特性。通过使用这些描述符,我们可以灵活地控制和定义对象的属性行为,例如限制某些属性只读、隐藏某些不需要枚举的属性等。

总的来说,对象的属性描述符提供了对对象属性行为进行详细控制和定义的能力,包括可配置性、可枚举性、可写性、获取和设置方法等。这使得我们能够更好地管理和操作对象中的各个属性。

目录
相关文章
|
24天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
监控 JavaScript 前端开发
确定使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript
【10月更文挑战第24天】选择使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript 是一个需要综合考虑多个因素的决策。需要根据脚本之间的依赖关系、页面加载性能要求、脚本的功能和重要性等因素来进行权衡。在实际应用中,需要通过测试和验证来确定最适合的加载方式,以提供更好的用户体验和页面性能。
|
1月前
|
监控 JavaScript 前端开发
使用 `defer` 属性异步加载 JavaScript
【10月更文挑战第24天】使用 `defer` 属性异步加载 JavaScript 是一种有效的提高页面性能和用户体验的方法。通过合理设置 `defer` 属性,可以在不影响页面渲染的情况下异步加载脚本,并确保脚本的执行顺序。在实际应用中,需要根据具体情况选择合适的加载方式,并注意处理可能出现的问题,以确保页面能够正常加载和执行。
|
2月前
|
移动开发 JavaScript 前端开发
原生js如何获取dom元素的自定义属性
原生js如何获取dom元素的自定义属性
76 4
|
2月前
|
缓存 JavaScript 前端开发
探索Vue.js中的计算属性与侦听器
【10月更文挑战第5天】探索Vue.js中的计算属性与侦听器
28 1
|
3月前
|
JavaScript 前端开发
JavaScript基础知识-枚举对象中的属性
关于JavaScript基础知识中如何枚举对象属性的介绍。
33 1
JavaScript基础知识-枚举对象中的属性
|
2月前
|
存储 JavaScript 前端开发
js中map属性
js中map属性
22 0
|
2月前
|
缓存 JavaScript 前端开发
深入理解Vue.js中的计算属性与侦听属性
【10月更文挑战第5天】深入理解Vue.js中的计算属性与侦听属性
31 0
|
2月前
|
缓存 JavaScript 前端开发
探索Vue.js中的计算属性与侦听器:深入理解与实践
【10月更文挑战第5天】探索Vue.js中的计算属性与侦听器:深入理解与实践
24 0
|
3月前
|
存储 JavaScript 前端开发
JS中的数组有哪些常用操作函数和属性
【9月更文挑战第7天】JS中的数组有哪些常用操作函数和属性
20 1