JavaScript学习笔记:对象属性的枚举

原创 2017年01月03日 17:44:00

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新增的方法,主要来遍历可迭代的对象(包括 Array , Map , Set , arguments 等),它主要用来获取对象的属性值,而 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
})

总结一下

其实这几个方法之间的差异主要在属性是否可可枚举,是来自己原型,还是实例。

方法 适用范围 描述
for...in 数组、对象 获取可枚举的实例和原型属性名
Object.keys() 数组,对象 返回可枚举的实例属性名组成的数组
Object.getPropertyNames() 数组、对象 返回除原型属性以外的所有属性(包括不可枚举的属性)名组成的数组
for...of 可迭代对象( Array , Map , Set , arguments 等) 返回属性值
版权声明:1083077511 qq 欢迎勾搭

JS 中枚举的使用方法

在JavaScript目前的版本中,没有枚举这个概念(当然,ECMA-262第三版中已经将enum作为关键字保留)。 然而,如同JavaScript中没有class一样,但我们仍然可以通过间接的方式—...
  • LANGZI7758521
  • LANGZI7758521
  • 2016年07月29日 13:36
  • 5953

javascript 的枚举

为了提升javascript 代码的可读性,jiasha var TestEnum = {}; TestEnum.FIRST  =1; TestEnum.SECOND =2; cons...
  • ISaiSai
  • ISaiSai
  • 2014年10月04日 11:14
  • 2310

JS 枚举型变量操作

JS   枚举型变量操作(用于全局变量等)(2010-03-18 21:10:20)转载标签:js分类: 程序语言  还有就是   in     运算符使用来判断对象是否包含有属性,你可以看一下这段代...
  • diligentcat
  • diligentcat
  • 2011年06月10日 11:21
  • 3128

JS中对象属性的可枚举性

在JS中,对象的属性分为可枚举和不可枚举,它是由属性的enumerable值决定的,true为可枚举,false为不可枚举 JS中预定义的原型属性一般是不可枚举的,而自己定义的属性一般可枚举 可以...
  • kongjunchao159
  • kongjunchao159
  • 2017年04月11日 15:15
  • 628

【js学习笔记-053】js中的面向对象技术------枚举类型

枚举类型是一种类型,它是值的有限集合,如果值定义为这个类型则该值是可以列出(或称可枚举)的。在C语言中,枚举类型是通过关键字enum声明的。Enum是ECMAScript5的保留字,很有可能js就会内...
  • pigpigpig4587
  • pigpigpig4587
  • 2013年10月09日 23:09
  • 6957

在js中仿java的枚举类型设计实例

简介 在javascript中,像EventTarget.addEventListener(),Document.createElement() 等方法,只接收指定字符串作为参数。比如: cons...
  • huuinn
  • huuinn
  • 2017年11月09日 21:14
  • 136

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

在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。 一、怎么判断属性是否可枚举 ...
  • mrhaoxiaojun
  • mrhaoxiaojun
  • 2017年04月27日 11:40
  • 467

JS 对象属性"可枚举"

对象属性可枚举,表示该属性的值不可修改,可认为该属性是常量。 如何定义不可枚举的属性? var obj = {name: 'jack', age:23} Object.definePro...
  • haojianfeng11
  • haojianfeng11
  • 2013年11月14日 23:57
  • 8548

unity3d--javascript的枚举类型写法

unity3d--javascript的枚举类型写法 哈哈,终于知道unity3d中js的枚举类型怎么写了 记录一下 enum RotationAxes { MouseXAndY =...
  • wanglang3081
  • wanglang3081
  • 2013年07月18日 11:16
  • 1037

java常见的枚举的写法

项目一忙起来,连写博客的心情斗米有了,这边也就做个记录关于java中常见枚举的记录 public enum EnumOperationPermission implements IEnumBehav...
  • u013651405
  • u013651405
  • 2015年09月15日 14:22
  • 2373
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JavaScript学习笔记:对象属性的枚举
举报原因:
原因补充:

(最多只允许输入30个字)