> 文章列表 > JavaScript对象的属性描述符(Property Descriptor)介绍

JavaScript对象的属性描述符(Property Descriptor)介绍

JavaScript对象的属性描述符(Property Descriptor)介绍

JavaScript对象属性描述符(Property Descriptor)介绍

JavaScript 中的对象(Object)是一个包含相关数据和方法的集合,通常由一些变量和函数组成,我们称之为对象里面的属性(property)和方法(method)。

【在JavaScript中,一般将Property译为属性、attribute译为特性,或不加区分都译为属性。】

本文重点介绍JavaScript对象的属性。

JavaScript 属性(property)概述

JavaScript 属性(property)是一个对象的成员,包含以下组成部分:

一个名称(也叫做键),它可能是字符串或符号值。

一个值,它可以是任何 JavaScript 值。具有函数值的属性也可以称为方法。

一些特性(attribute),它们指定了属性的读取和写入方式。属性可能具有 configurable、enumerable 和 writable 特性(attributes)。

【见 https://developer.mozilla.org/zh-CN/docs/Glossary/Property/JavaScript 】

在JS中,对象的属性(property)也称为名值对(键/值对),包括属性名和属性值。属性名可以是包含空字符串在内的任意字符串,一个对象中不能存在两个同名的属性。属性值可以是任意类型的数据。关于JavaScript 属性(property)可参见 https://blog.csdn.net/cnds123/article/details/125406135

本文重点介绍属性描述符。

属性描述符(Property Descriptor

ES5中定义了一个属性描述符对象(property descriptor)。其作用是给对象的属性增加更多的控制。

【Property Descriptor(属性描述符),也有人称为Property Attributes。】

描述符分类

configurable

enumerable

value

writable

get

set

数据描述符

可以

可以

可以

可以

不可以

不可以

存取描述符

可以

可以

不可以

不可以

可以

可以

JavaScript的数据描述符和访问器描述符都是对象。它们共享以下可选键(请注意:这里提到默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

configurable

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

enumerable

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

数据描述符还具有以下可选键:

value

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

writable

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

存取描述符还具有以下可选键:

get

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

set

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

更多关于属性描述符类型(property descriptor types )以及他们特/属性(attributes)的信息可以查看https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

描述符方法用于设置属性描述符。描述符方法常用的有:

Object.defineProperty(obj, name, descriptor)方法用于创建或配置对象的一个属性描述符,返回配置后的对象。

Object.defineProperties(obj, descriptors)方法用于创建或配置对象的多个描述符,返回配置后的对象。

Object.preventExtensions(object)方法防止向对象添加属性。

Object.seal(object)方法防止向对象添加属性。

Object.freeze(object)方法防止对对象进行任何更改。

Object.getOwnPropertyDescriptor(obj, name)方法用于查询对象一个属性的描述符,查询结果以对象的形式返回。

属性描述符的使用讲解

Object.defineProperty()方法

Object.defineProperty()方法可以为对象添加属性,或者修改现有属性。如果指定的属性名在对象中不存在,则执行添加操作;如果在对象中存在同名属性,则执行修改操作。

使用属性描述符的基本语法如下:

Object.defineProperty(object, propertyname, descriptor);

参数说明如下:

object:指定要添加或修改属性的对象,可以是 JavaScript 对象或者 DOM 对象。

propertyname:表示属性名的字符串。

descriptor:定义属性的描述符,包括对数据属性或访问器属性。

返回值为已修改的对象。

【Object.defineProperty方法,可见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty】

从一段简单的代码讲起:

var obj = { };

Object.defineProperty(obj, 'attr', { value: 1 });

上面代码给obj对象增加了一个名为attr的属性,值为1。相当于:

var obj = { };

obj.attr = 1;

相比起来,Object.defineProperty 的写法看似更为复杂。但是,它最大的奥秘在于其第三个参数。现在看看使用属性的描述符的情况:

let obj = { };
Object.defineProperty(obj, 'property1', {value: 10,writable: false
});
console.log(obj.property1); //10
obj.property1 = 20; // 注意该句不影响obj.property1的值
console.log(obj.property1); //10

为了测试上面JavaScript程序代码,我在这里将其放在标签

<script>

</script>之间

保存文件名为:JS对象描述符writables示例.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

看到了吗?执行以上程序可以发现,两次输出的property1的值都是10.

这样的结果会有点莫名其妙,赋值语句的执行没报异常,又不影响obj.property1的值。如果在大段的代码中出现这样的问题,很难排查出来。有什么应对吗?只要以严格模式运行代码,就会产生异常。

【严格模式是在 ECMAScript5(ES5)中引入的,在严格模式下,JavaScript 对语法的要求会更加严格,一些在正常模式下能够运行的代码,在严格模式下将不能运行。

要启用严格模式,您只需要在JavaScript程序代码的开头添加"use strict";或'use strict';指令即可】

将上面代码改为:

'use strict'; // 进入严格模式
let obj = { };
Object.defineProperty(obj, 'property1', {value: 10,writable: false
});
console.log(obj.property1); //10
obj.property1 = 20; // 注意该句报异常(throw exception)

为了测试上面代码,将其放在标签

<script>

</script>之间

保存文件名为:JS对象描述符writables示例(严格模式).html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

现在看看数据描述符 enumerable的作用,它可以控制属性是否能被枚举,示例源码如下:

<script>
var obj = {str1: "a",str2: "bb",str3: "ccc"
};
Object.defineProperty(obj, "str2", {enumerable:false}); // 请注意此句的作用
for (var i in obj) { console.log(obj[i]); 
}
</script>

保存文件名为:JS对象描述符enumerable示例.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

现在介绍存取描述符get、set

getter和setter取代了数据属性中的value和writable属性。

如果只设置了set方法,读取对象的属性值会返回undefined。通常set和get方法成对出现。

示例源码如下:

<script>
let o = {};
Object.defineProperty(o, 'a', {configurable: true,enumerable: true,get: function() {return 10}
})console.log(o.a) // 10
o.a = 20
console.log(o.a) // 10
</script>

保存文件名为:JS存取描述符get和set示例.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

 这两个描述符的使用就有很大的想象空间了,如,可以用来校验输入值,看下面这个例子:

<script>
let obj = { realAge: 0 }Object.defineProperty(obj, 'age', {get: function() {return this.realAge},set: function(value) {const temp = Number(value);if(isNaN(temp)) throw TypeError('Not A Number')  //检测存入的值,如果无法转换成数字就会抛出自定义异常this.realAge = temp;}
})obj.age = '22'
console.log(obj.age) // 22
obj.age='abc';  //引发异常
console.log(obj.age) // TypeError:Not A Number
</script>

保存文件名为:JS存取描述符get和set示例2.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

上例可以采用如下便捷写法: 

<script>
let obj = { realAge: 0,get age() {  // 函数名 age 就是属性名return this.realAge},set age(value) { // 函数名 age 就是属性名const temp = Number(value);if(isNaN(temp)) throw TypeError('Not A Number')  //检测存入的值,如果无法转换成数字就会抛出自定义异常this.realAge = temp;}
}obj.age = '22'
console.log(obj.age) // 22
obj.age='abc';  //引发异常
console.log(obj.age) // TypeError:Not A Number
</script>

你可以保存文件名为:JS存取描述符get和set示例2b.html,用浏览器打开它测试看看。

前面介绍了设置属性描述符,那如何获取已设置的描述符呢?

Object.getOwnPropertyDescriptor方法

使用 Object.getOwnPropertyDescriptor() 方法能够获取对象属性的描述符。具体用法如下:

Object.getOwnPropertyDescriptor(object, propertyname);

参数 object 表示指定的对象,propertyname 表示属性的名称。

返回值为属性的描述符对象。

示例源码如下:

<script>
let obj = { a: 10,say: function(){return 'Hello'; }
};let desc1 = Object.getOwnPropertyDescriptor(obj, 'a'); //获取描述符状况
console.dir(desc1);
let desc2 = Object.getOwnPropertyDescriptor(obj, 'a'); //获取描述符状况
console.dir(desc2);
</script>

保存文件名为:JS获取描述符状况.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:

 

参考
中文 https://www.w3schools.cn/js/js_object_es5.html【英文 https://www.w3schools.com/js/js_object_es5.asp】
畅谈JS属性描述符和Proxy https://zhuanlan.zhihu.com/p/355217413
属性描述器https://blog.51cto.com/u_15069482/4171311