作为js特有的一个语句,刚接触时只知道用来枚举对象属性,因为之前的实际工作中用得其实不多,后来看了几本书越发警惕for-in的局限性,今天参照书中的讲解明确一下。
《JS高级程序设计》:
1.for-in是一种精准的迭代语句,可以用来枚举对象属性。所有属性都会被枚举一遍。
2.由于对象的属性是无序的,所以for-in枚举对象属性是不可预测的,因浏览器而异。
3.在ES3中如果迭代的对象的变量值是null或undefined,会抛出错误;在ES5中只是不执行循环体,故而迭代前应检测其值不为null或undefined。
这里有个值得注意的问题是,对象的属性包括继承自原型的属性、函数和用户自定义的属性。因此在《JS语言精粹》中Douglas提到:
1.有必要过滤掉那些你不期望的值,最常用的过滤器是hasOwnProperty(屏蔽继承自原型的属性)方法和typeof操作符(检测属性值类型,比如‘function’);
2.如果想以特定顺序迭代,建议抛弃for-in改用for循环,先建立一个数组并在其中将期望的属性以指定顺序排列;
以上对于在ES5中编程的情况。ES6以前,对象属性名是字符串,为了避免在实际生产中“命名冲突”的问题,ES6中引入了一个原始类型symbol。symbol类型的意义在于,创建一个独一无二的值,比如let
a=Symbol();其值是一个类似于字符串的存在,自此对象的属性名有两种数据类型:字符串和symbol值。
《ES6标准入门》(第2版):
ES6一共有6总方法可以遍历对象属性。
1.for-in遍历对象自身的和继承的可枚举属性(不包含symbol)。
2.Object.keys(obj)返回数据,包括对象自身的(不含继承)所有可枚举属性(不包含symbol);
3.Object.getOwnPropertyNames(obj)返回数组,返回对象自身的所有属性(不包含symbol但包含不可枚举)
4.Object,getOwnPropertySymbols(obj)返回数组,包含对象自身所有symbol属性。
5.Reflect.ownKeys(obj)返回数组,包含对象自身所有属性,不管属性名是字符串或symbol,也不管是否可枚举。
6.Reflect.enumerate(obj)返回一个Iterator对象,遍历对象自身的和继承的可枚举属性(不包含symbol),同for-in。
以上6种方法遵循同样的属性遍历次序规则:
1.先遍历属性名为数值的属性;
2.再遍历属性名为字符串的属性;
3.最后遍历所有属性名为symbol值的属性;