对象属性的可枚举性

JavaScript中对象的属性分为两种:数据属性访问器属性。然后根据具体的上下文环境的不同,又可以将属性分为:原型属性实例属性。原型属性是定义在对象的原型(prototype)中的属性,而实例属性一方面来自构造的函数中,然后就是构造函数实例化后添加的新属性。

在JavaScript中除了检测对象的属性是否存在,还会经常对对象的属性进行遍历(枚举)。而在JavaScript中遍历一个对象的属性并不太简单,主要有两个原因:

  • JavaScript中的对象通常都处在某个原型链中,它会从一个或多个的上层原型上继承一些属性
  • JavaScript中的属性不光有值,它还有一些除了值以外的其他特性,其中一个影响属性遍历的特性就是[[Enumerable]],如果该值为true,则这个属性是可枚举的,否则反之

这篇文章将总结有关于JavaScript中对象属性枚举的几种方法:

  • for ... in
  • Object.keys()
  • Object.getOwnPropertyNames()
  • for ... of

for ... in

for...in循环可以遍历对象中所有可枚举的对象属性(包括对象自有属性和继承的属性)。不过需要注意的是,使用for...in循环遍历对象属性时返回的属性会因为各个浏览器不同导致对象属性遍历的顺序有可能不是当初构建时的顺序。

var obj = {
    ‘x‘: 1,
    ‘y‘: 2,
    ‘z‘: 3
}
obj.propertyIsEnumerable(‘toString‘); // false,不可枚举

for (prop in obj) {
    console.log(prop); // 输出x,y,z;但不会输出toString
}

其实for...in操作的主要目的就是遍历对象的属性,如果只需要获取对象的实例属性(跳过继承属性),可以使用hasOwnProperty()进行过滤:

for (prop in obj) {
    if (!obj.hasOwnProperty(prop)) continue; // 跳过继承属性
}

如此一来,可以这样来使用for...in循环遍历对象属性:

(function () {
    var getEnumPropertyNames = function (obj) {
        if (typeof obj !== ‘object‘) throw TypeError(); // 参数必须是对象
        var props = []; // 将要返回的数组
        for (var prop in obj) { // 遍历所有可枚举的属性
            if (obj.hasOwnProperty(prop)) { //判断是否是自有属性
                props.push(prop); //将属性名添加到数组中
            }
        }
        return props; //返回这个数组
    }

    // 实例化
    var obj = {
       ‘x‘: 1,
       ‘y‘:2
    }
    obj.propertyIsEnumerable(‘toString‘)
    var propertys = getEnumPropertyNames(obj);
    console.log(propertys.length);       //2
    console.log(propertys.join(","));   //x,y
})()

Object.keys()

Object.keys()方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,数组中属性名的排列顺序和使用for...in循环遍历该对象时返回的顺序一致。两者最大的区别在于for...in还会遍历出一个对象从其原型链上继承到的可枚举属性

Object.keys() 返回一个所有元素为字符串的数组,其元素来自于从给定的对象上面可直接枚举的属性。这些属性的顺序与手动遍历该对象属性时的一致。

var obj = {
    ‘x‘: 1,
    ‘y‘: 2,
    ‘z‘: 3
}
obj.propertyIsEnumerable(‘toString‘);

console.log(Object.keys(obj)); // ["x", "y", "z"]

Object.keys()可以遍历对象可枚举的自身属性。也就是说对象的属性不是从原型链上继承下来的。

注意:在 ES5 环境,如果传入的参数不是一个对象,而是一个字符串,那么它会报 TypeError。在 ES6 环境,如果传入的是一个非对象参数,内部会对参数作一次强制对象转换,如果转换不成功会抛出 TypeError。

// 在 ES5 环境
Object.keys(‘foo‘); // TypeError: "foo" is not an object

// 在 ES6 环境
Object.keys(‘foo‘); // ["0", "1", "2"]

// 传入 null 对象
Object.keys(null); // Uncaught TypeError: Cannot convert undefined or null to object

// 传入 undefined
Object.keys(undefined); // Uncaught TypeError: Cannot convert undefined or null to object

Object.getOwnPropertyNames()

Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组,但不会获取原型链上的属性。该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过for...in(或 Object.keys())迭代该对象属性时一致。 数组中不可枚举属性的顺序未定义。

// 类数组对象
var obj = {
    0: "a",
    1: "b",
    2: "c"
};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]

for...of

for...of为ES6新增的方法,主要来遍历可迭代的对象(包括ArrayMapSetarguments等),它主要用来获取对象的属性值,而for...in主要获取对象的属性名。

var colors = [‘red‘, ‘green‘, ‘blue‘];
colors.length = 5;
colors.push(‘yellow‘);

for (var i in colors) {
  console.log(colors[i]); // red green blue yellow
}

for (var j of colors) {
  console.log(j); // red green blue undefined undefined yellow
}

可以看到使用for...of可以输出包括数组中不存在的值在内的所有值。

其实除了使用for...of直接获取属性值外,我们也可以利用Array.prototype.forEach()来达到同样的目的。

var colors = [‘red‘, ‘green‘, ‘blue‘];
colors.foo = ‘hello‘;

Object.keys(colors).forEach(function(elem, index) {
  console.log(colors[elem]); // red green blue hello
  console.log(colors[index]); // red green blue undefined
});

colors.forEach(function(elem, index) {
  console.log(elem); // red green blue
  console.log(index); // 0 1 2
})

总结

这几个方法之间的差异主要在属性是否可可枚举,是来自己原型,还是实例。著作权归作者所有。

原文: https://www.w3cplus.com/javascript/how-do-i-enumerate-the-properties-of-a-javascript-object.html?utm_source=tuicool&utm_medium=referral ? w3cplus.com

时间: 2024-10-08 19:43:05

对象属性的可枚举性的相关文章

JavaScript服务器端开发技术(对象属性的枚举与查询)

既然对象是属性的集合,那么检测与枚举集合中的属性就是一项重要任务.对此,我们来分别看一下ES3和ES5提供的解决方案. 1)     ES3枚举方案 示例代码: var contacts={ ID:[0,1,2,3,4,5], names:["Zero","One","Two","Three","Four","Five"], addresses:[ { Street:"ABC&

js对象中什么是可枚举性(enumerable)?

说到枚举,可能很多人都会想到枚举类型,但在javascript对象中有一个属性为可枚举性,他是什么呢? 概念 可枚举性(enumerable)用来控制所描述的属性,是否将被包括在for...in循环之中.具体来说,如果一个属性的enumerable为false,下面三个操作不会取到该属性.* for..in循环* Object.keys方法* JSON.stringify方法 enumerable "隐身术" var o = {a:1, b:2}; o.c = 3; Object.de

对象属性的增删改查、特性已经序列化

1)在javascript中,只有查询属性时才会体会到继承的存在,而设置属性则和继承无关,这使程序员可以有选择的覆盖继承的属性. 2)如果o继承了原型上的属性x,而这个属性是具有setter方法的存取器(accessor)属性,这时会调用setter方法而不是给o创建一个属性x. 注意: setter方法是由对象o调用的,而不是定义这个属性的原型调用的,因此setter定义任何属性,这个操作只针对o本身,而不会改变原型链. 3)属性访问并不总是返回或设置一个值,访问 null 或 undefin

js对象属性特征

enumerable和configurable (function(){ 'use strict'; var point={x:1,y:2,z:3}; Object.defineProperty(point,'x',{ enumerable:false,//对象属性是否可枚举 configurable:false //对象属性是否可配置,不能删除,注意值是可以修改的 }); delete point.x;//x属性不可配置,所以x属性没有被删除,在严格模式下会抛出错误,非严格模式忽略 conso

对象转换成json串时,将null属性去除;以及枚举类的使用

import java.lang.reflect.Field; import java.util.Date; import java.util.Map; import org.hibernate.Hibernate; import abc.dao.Student; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.PropertyPreFilter; impo

JavaScript服务器编程(对象属性枚举中应当避免原型污染问题)

前面文章中讨论了JS开发中对象属性枚举的ES3和ES5方案并给出了一组常用工具函数,其实,企业开发中真正应用时还存在不少问题.本文想基于前文进一步探讨一下有关原型污染的问题.由于JS的先天不足,有关原型污染背后隐藏着一个大的"故事",以后我们的文章中还要涉及其中一些情节. 问题 前面在讨论使用in运算符检测对象中是否存在属性的方案,但是通过所举的示例也发现一个问题,例如: console.log('"ID" in contacts: ',"ID"

3.Object.keys() 取得对象中所有可枚举的属性

Object.keys() 取得对象中所有可枚举的属性 function Person(){ }Person.prototype.name="summer";Person.prototype.age=20;Person.prototype.job="enginner";Person.prototype.sayName=function(){ console.log(this.name);} var keys=Object.keys(Person.prototype)

for-in枚举对象属性

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>for-in 枚举</title> </head> <body> <script> function Person(){ this.name="person"; this.age=10; this.se

ja对象属性—枚举、检查、删除

前言 我们经常需要操作对象的属性.这里记录ES5中操作对象属性的API和它们之间的差异. 枚举属性 for/in遍历对象中的所有可枚举属性(包括自有属性和继承属性) var obj = {name:"小花",age:18}; var obj2 = Object.create(obj); obj2.like = "骨头"; for(item in obj2){ // 将obj中的所有可枚举属性名以字符串形式分别赋值给itemtypeof item; => str