在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

一、怎么判断属性是否可枚举

js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,如果你写出这样的代码遍历其中的属性:

  1. var num = new Number();
  2. for(var pro in num) {
  3. console.log("num." + pro + " = " + num[pro]);
  4. }

它的输出结果会是空。这是因为Number中内置的属性是不可枚举的,所以不能被for…in访问到。

Object对象的propertyIsEnumerable()方法可以判断此对象是否包含某个属性,并且这个属性是否可枚举。

需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false

二、枚举性的作用

属性的枚举性会影响以下三个函数的结果:

for…in

Object.keys()

JSON.stringify

先看一个例子,按如下方法创建kxy对象:

  1. function Person() {
  2. this.name = "KXY";
  3. }
  4. Person.prototype = {
  5. constructor: Person,
  6. job: "student",
  7. };
  8.  
  9. var kxy = new Person();
  10. Object.defineProperty(kxy, "sex", {
  11. value: "female",
  12. enumerable: false
  13. });

其中用defineProperty为对象定义了一个名为”sex”的不可枚举属性

接下来做以下验证:
a.

  1. for(var pro in kxy) {
  2. console.log("kxy." + pro + " = " + kxy[pro]);
  3. }

结果:

  1. kxy.name = KXY
  2. kxy.constructor = function Person() {
  3. this.name = "KXY";
  4. }
  5. kxy.job = student

b.

  1. console.log(Object.keys(kxy));

返回结果:["name"]
只包含”name”属性,说明该方法只能返回对象本身具有的可枚举属性。

c.

  1. console.log(JSON.stringify(kxy));

返回结果:{"name":"KXY"}
此方法也只能读取对象本身的可枚举属性,并序列化为JSON字符串(通过typeof JSON.stringify(kxy)得到string类型)。

Object.defineProperty()

上面用到了Object.defineProperty()方法,下面讲解下。

语法

  1. Object.defineProperty(object, propertyname, descriptor)

参数:

  • object:必需。 要在其上添加或修改属性的对象。 这可能是一个本机 JavaScript 对象(即用户定义的对象或内置对象)或 DOM 对象。

  • propertyname:必需。 一个包含属性名称的字符串。

  • descriptor:必需。 属性描述符。 它可以针对数据属性或访问器属性。

返回值:已修改对象。

备注:
可使用 Object.defineProperty 函数来执行以下操作:

  • 向对象添加新属性。 当对象不具有指定的属性名称时,发生此操作。

  • 修改现有属性的特性。 当对象已具有指定的属性名称时,发成此操作。

描述符对象中会提供属性定义,用于描述数据属性或访问器属性的特性。 描述符对象是 Object.defineProperty 函数的参数。

若要向对象添加多个属性或修改多个现有属性,可使用 Object.defineProperties 函数 (JavaScript)。

异常

如果以下任一条件为 true,则引发 TypeError 异常:

  • object 参数不是对象。

  • 此对象不可扩展且指定的属性名称不存在。

  • descriptor 具有 value 或 writable 特性,并且具有 get 或 set 特性。

  • descriptor 具有 get 或 set 特性,上述特性不是函数且已定义。

  • 指定的属性名称已存在,现有属性具有 false 的 configurable 特性,且 descriptor 包含一个或多个与现有属性中特性不同的特性。 但是,当现有属性具有 false 的 configurable 特性和 true 的 writable 特性时,则允许 value 或 writable 特性不同。

添加数据属性

在以下示例中,Object.defineProperty 函数向用户定义的对象添加数据属性。 若改为向现有的 DOM 对象添加属性,则取消对 var = window.document 行的注释。

  1. var newLine = "<br />";
  2.  
  3. // Create a user-defined object.
  4. var obj = {};
  5.  
  6. // Add a data property to the object.
  7. Object.defineProperty(obj, "newDataProperty", {
  8. value: 101,
  9. writable: true,
  10. enumerable: true,
  11. configurable: true
  12. });
  13.  
  14. // Set the property value.
  15. obj.newDataProperty = 102;
  16. document.write("Property value: " + obj.newDataProperty + newLine);
  17.  
  18. // Output:
  19. // Property value: 102

若要列出对象属性,请将以下代码添加到此示例中。

  1. var names = Object.getOwnPropertyNames(obj);
  2. for (var i = 0; i < names.length; i++) {
  3. var prop = names[i];
  4.  
  5. document.write(prop + ': ' + obj[prop]);
  6. document.write(newLine);
  7. }
  8.  
  9. // Output:
  10. // newDataProperty: 102

修改数据属性

若要修改对象的属性特性,请将以下代码添加到前面所示的 addDataProperty 函数。 descriptor 参数只包含 writable 特性。 其他数据属性特性保持不变。

  1. // Modify the writable attribute of the property.
  2. Object.defineProperty(obj, "newDataProperty", { writable: false });
  3.  
  4. // List the property attributes by using a descriptor.
  5. // Get the descriptor with Object.getOwnPropertyDescriptor.
  6. var descriptor = Object.getOwnPropertyDescriptor(obj, "newDataProperty");
  7. for (var prop in descriptor) {
  8. document.write(prop + ': ' + descriptor[prop]);
  9. document.write(newLine);
  10. }
  11.  
  12. // Output
  13. // writable: false
  14. // value: 102
  15. // configurable: true
  16. // enumerable: true

添加访问器属性

在以下示例中,Object.defineProperty 函数向用户定义的对象添加访问器属性。

  1. var newLine = "<br />";
  2.  
  3. // Create a user-defined object.
  4. var obj = {};
  5.  
  6. // Add an accessor property to the object.
  7. Object.defineProperty(obj, "newAccessorProperty", {
  8. set: function (x) {
  9. document.write("in property set accessor" + newLine);
  10. this.newaccpropvalue = x;
  11. },
  12. get: function () {
  13. document.write("in property get accessor" + newLine);
  14. return this.newaccpropvalue;
  15. },
  16. enumerable: true,
  17. configurable: true
  18. });
  19.  
  20. // Set the property value.
  21. obj.newAccessorProperty = 30;
  22. document.write("Property value: " + obj.newAccessorProperty + newLine);
  23.  
  24. // Output:
  25. // in property set accessor
  26. // in property get accessor
  27. // Property value: 30

若要列出对象属性,请将以下代码添加到此示例中。

  1. var names = Object.getOwnPropertyNames(obj);
  2. for (var i = 0; i < names.length; i++) {
  3. var prop = names[i];
  4.  
  5. document.write(prop + ': ' + obj[prop]);
  6. document.write(newLine);
  7. }
  8. // Output:
  9. // in property get accessor
  10. // newAccessorProperty: 30

修改访问器属性

若要修改对象的访问器属性,请将以下代码添加前面所示的代码。 descriptor 参数只包含 get 访问器定义。 其他属性特性保持不变。

  1. // Modify the get accessor.
  2. Object.defineProperty(obj, "newAccessorProperty", {
  3. get: function () { return this.newaccpropvalue; }
  4. });
  5.  
  6. // List the property attributes by using a descriptor.
  7. // Get the descriptor with Object.getOwnPropertyDescriptor.
  8. var descriptor = Object.getOwnPropertyDescriptor(obj, "newAccessorProperty");
  9. for (var prop in descriptor) {
  10. document.write(prop + ': ' + descriptor[prop]);
  11. document.write(newLine);
  12. }
  13.  
  14. // Output:
  15. // get: function () { return this.newaccpropvalue; }
  16. // set: function (x) { document.write("in property set accessor" + newLine); this.newaccpropvalue = x; }
  17. // configurable: true
  18. // enumerable: true

修改 DOM 元素上的属性

下面的示例演示如何通过使用 Object.getOwnPropertyDescriptor 函数来获取和修改属性的属性描述符,从而自定义内置 DOM 属性。 对于此示例中,必须通过使用 ID 为“div”的 DIV 元素。

  1. // Get the querySelector property descriptor.
  2. var descriptor = Object.getOwnPropertyDescriptor(Element.prototype, "querySelector");
  3.  
  4. // Make the property read-only.
  5. descriptor.value = "query";
  6. descriptor.writable = false;
  7. // Apply the changes to the Element prototype.
  8. Object.defineProperty(Element.prototype, "querySelector", descriptor);
  9.  
  10. // Get a DOM element from the HTML body.
  11. var elem = document.getElementById("div");
  12.  
  13. // Attempt to change the value. This causes the revised value attribute to be called.
  14. elem.querySelector = "anotherQuery";
  15. document.write(elem.querySelector);
  16.  
  17. // Output:
  18. // query

Object.keys()

返回对象的可枚举属性和方法的名称。

语法

  1. Object.keys(object)

参数object:必需。包含属性和方法的对象。这可以是您创建的对象或现有文档对象模型 (DOM) 对象。
返回值:一个数组,其中包含对象的可枚举属性和方法的名称。
异常:如果为 object 参数提供的值不是对象的名称,则将引发 TypeError 异常。

备注

keys 方法仅返回可枚举属性和方法的名称。若要返回可枚举的和不可枚举的属性和方法的名称,可使用 Object.getOwnPropertyNames 函数 (JavaScript)。
有关属性的 enumerable 特性的信息,请参见 Object.defineProperty 函数 (JavaScript)和 Object.getOwnPropertyDescriptor 函数 (JavaScript)。

下面的示例创建一个对象,该对象具有三个属性和一个方法。然后使用 keys 方法获取该对象的属性和方法。

  1. // Create a constructor function.
  2. function Pasta(grain, width, shape) {
  3. this.grain = grain;
  4. this.width = width;
  5. this.shape = shape;
  6.  
  7. // Define a method.
  8. this.toString = function () {
  9. return (this.grain + ", " + this.width + ", " + this.shape);
  10. }
  11. }
  12.  
  13. // Create an object.
  14. var spaghetti = new Pasta("wheat", 0.2, "circle");
  15.  
  16. // Put the enumerable properties and methods of the object in an array.
  17. var arr = Object.keys(spaghetti);
  18. document.write (arr);
  19.  
  20. // Output:
  21. // grain,width,shape,toString

下面的示例显示 Pasta 对象中以字母“g”开头的所有可枚举属性的名称。

  1. // Create a constructor function.
  2. function Pasta(grain, width, shape) {
  3. this.grain = grain;
  4. this.width = width;
  5. this.shape = shape;
  6. }
  7.  
  8. var polenta = new Pasta("corn", 1, "mush");
  9.  
  10. var keys = Object.keys(polenta).filter(CheckKey);
  11. document.write(keys);
  12.  
  13. // Check whether the first character of a string is "g".
  14. function CheckKey(value) {
  15. var firstChar = value.substr(0, 1);
  16. if (firstChar.toLowerCase() == "g")
  17. return true;
  18. else
  19. return false;
  20. }
  21.  
  22. // Output:
  23. // grain

Object.getOwnPropertyNames()

返回对象自己的属性的名称。一个对象的自己的属性是指直接对该对象定义的属性,而不是从该对象的原型继承的属性。对象的属性包括字段(对象)和函数。

语法

  1. Object.getOwnPropertyNames(object)

参数:object,必需。包含自己的属性的对象。
返回值:一个数组,其中包含对象自己的属性的名称。
异常:如果为 object 参数提供的值不是对象的名称,则将引发 TypeError 异常。

备注

getOwnPropertyNames 方法同时返回可枚举的和不可枚举的属性和方法的名称。若要仅返回可枚举的属性和方法的名称,可使用 Object.keys 函数 (JavaScript)。

下面的示例创建一个对象,该对象具有三个属性和一个方法。然后使用 getOwnPropertyNames 方法获取该对象自己的属性(包括方法)。

js代码:

  1. function Pasta(grain, width, shape) {
  2. // Define properties.
  3. this.grain = grain;
  4. this.width = width;
  5. this.shape = shape;
  6. this.toString = function () {
  7. return (this.grain + ", " + this.width + ", " + this.shape);
  8. }
  9. }
  10.  
  11. // Create an object.
  12. var spaghetti = new Pasta("wheat", 0.2, "circle");
  13.  
  14. // Get the own property names.
  15. var arr = Object.getOwnPropertyNames(spaghetti);
  16. document.write (arr);
  17.  
  18. // Output:
  19. // grain,width,shape,toString

下面的示例显示了使用 Pasta 构造函数构造的 spaghetti 对象中以字母“S”开头的属性名。

  1. function Pasta(grain, size, shape) {
  2. this.grain = grain;
  3. this.size = size;
  4. this.shape = shape;
  5. }
  6.  
  7. var spaghetti = new Pasta("wheat", 2, "circle");
  8.  
  9. var names = Object.getOwnPropertyNames(spaghetti).filter(CheckKey);
  10. document.write(names);
  11.  
  12. // Check whether the first character of a string is 's'.
  13. function CheckKey(value) {
  14. var firstChar = value.substr(0, 1);
  15. if (firstChar.toLowerCase() == 's')
  16. return true;
  17. else
  18. return false;
  19. }
  20. // Output:
  21. // size,shape

参考

https://msdn.microsoft.com/zh...
https://msdn.microsoft.com/li...
https://msdn.microsoft.com/zh...

相关阅读:JS基础篇--JS apply的巧妙用法以及扩展到Object.defineProperty的使用

JS中的可枚举属性与不可枚举属性以及扩展的更多相关文章

  1. JS中的prototype、__proto__与constructor属性

    作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...

  2. js中的可枚举属性与不可枚举属性

    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for…in查找遍历到. 一.怎么判断属性是否可枚举 js中基本包 ...

  3. JavaScript中的可枚举属性与不可枚举属性

    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for…in查找遍历到. 一.怎么判断属性是否可枚举 js中基本包 ...

  4. JS对象的可枚举属性和不可枚举属性

    昨天在写文章(转载)的时候发现了有些对象的方法是分可枚举性和不可枚举性的.简单的查了一下资料,今天来捋一捋啥是对象的可枚举啥是不可枚举. 可枚举性: 对象的每一个属性都有一个描述对象,用来描述和控制该 ...

  5. <JavaScript>可枚举属性与不可枚举属性

    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for…in查找遍历到. 一.怎么判断属性是否可枚举 js中基本包 ...

  6. 在C#中如何读取枚举值的描述属性

    在C#中,有时候我们需要读取枚举值的描述属性,也就是说这个枚举值代表了什么意思.比如本文中枚举值 Chinese ,我们希望知道它代表意思的说明(即“中文”). 有下面的枚举: 1 2 3 4 5 6 ...

  7. 详解JS中DOM 元素的 attribute 和 property 属性

    一.'表亲戚':attribute和property 为什么称attribute和property为'表亲戚'呢?因为他们既有共同处,也有不同点. attribute 是 dom 元素在文档中作为 h ...

  8. JS中的实例方法、静态方法、实例属性、静态属性

    一.静态方法与实例方法的例子: 我们先来看一个例子来看一下JS中的静态方法和实例方法到底是什么? 静态方法: function A(){} A.col='red'  //静态属性 A.sayMeS=f ...

  9. JS中构造函数与原型对象的同名属性,实例会取哪一个

    构造函数与原型对象的同名属性,实例会取哪一个? 看了下面的过程,再回忆JS高程3里关于这部分的示意图.实例my在new的时候,本身就获得了a属性,所以my.a是1,倘若在new的时候如果没有赋予a属性 ...

随机推荐

  1. 吴恩达机器学习笔记15-假设陈述(Hypothesis Representation)

    在分类问题中,要用什么样的函数来表示我们的假设呢?此前说过,希望我们的分类器的输出值在0 和1 之间,因 此,我们希望想出一个满足某个性质的假设函数,这个性质是它的预测值要在0 和1 之间.回顾在一开 ...

  2. Git使用详细教程(1):工作区、暂存区、本地仓库、远程仓库

    之前的写过一篇如何在服务器上搭建Git服务Git服务器搭建,接下来的一段时间,我将详细的讲解Git的使用.看如下一张图片,本篇主要理解一些基本概念. 图中几个名词的意思如下: workspace: 工 ...

  3. 【Spark调优】小表join大表数据倾斜解决方案

    [使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...

  4. Oracle创建表空间、用户管理、角色管理

    内容:Oracle创建表空间.用户管理.角色管理 1.用系统用户登录Oracle 默认的系统用户: sys/system.sysman.scott sys:权限最大,超级用户,可以完成所有任务, 默认 ...

  5. 使用maven插件构建docker镜像

    为什么要用插件 主要还是自动化的考虑,如果额外使用Dockerfile进行镜像生成,可能会需要自己手动指定jar/war位置,并且打包和生成镜像间不同步,带来很多琐碎的工作. 插件选择 使用比较多的是 ...

  6. Java核心技术及面试指南 流程控制方面的面试题答案

    2.2.5.1 switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 1 switch里可以用char,byte,short,int这些基本类型,以及它们的封装类.  ...

  7. springBoot(6)---过滤器,监听器,拦截器

    过滤器,监听器,拦截器 一.理解它们 看里十几篇博客,总算有点小明白,总的来讲,两张图可以让我看明白点. 通过两幅图我们可以理解拦截器和过滤器的特点 1.过滤器 过滤器是在请求进入tomcat容器后, ...

  8. threadid=1: thread exiting with uncaught exception (group=0x40fca9a8)的问题

    今天在项目开发中碰到了这样一个问题: 项目在Nexus5[Android 6.0]上面运行正常,在华为荣耀6[Android 4.4.2]上面运行到指定activity崩溃(不是应用启动崩溃):然后后 ...

  9. Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...

  10. SpringBoot自动配置源码调试

    之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...