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程序代码,我在这里将其放在标签
之间
保存文件名为: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)
为了测试上面代码,将其放在标签
之间
保存文件名为:JS对象描述符writables示例(严格模式).html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:
现在看看数据描述符 enumerable的作用,它可以控制属性是否能被枚举,示例源码如下:
保存文件名为:JS对象描述符enumerable示例.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:
现在介绍存取描述符get、set
getter和setter取代了数据属性中的value和writable属性。
如果只设置了set方法,读取对象的属性值会返回undefined。通常set和get方法成对出现。
示例源码如下:
保存文件名为:JS存取描述符get和set示例.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:
这两个描述符的使用就有很大的想象空间了,如,可以用来校验输入值,看下面这个例子:
保存文件名为:JS存取描述符get和set示例2.html,用浏览器打开它,再按下 F12键打开浏览器的“控制台”(console) 面板,显示效果如下:
上例可以采用如下便捷写法:
你可以保存文件名为:JS存取描述符get和set示例2b.html,用浏览器打开它测试看看。
前面介绍了设置属性描述符,那如何获取已设置的描述符呢?
Object.getOwnPropertyDescriptor方法
使用 Object.getOwnPropertyDescriptor() 方法能够获取对象属性的描述符。具体用法如下:
Object.getOwnPropertyDescriptor(object, propertyname);
参数 object 表示指定的对象,propertyname 表示属性的名称。
返回值为属性的描述符对象。
示例源码如下:
保存文件名为: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