今天来深究一下for in 的背后都存在什么
先看一个小例子
1.思考一下下面的代码会输出什么?
Object.prototype.xiaom = function () { console.log('前端老酒馆') }
let a = {}
for(let key in a) {
console.log(key) // 打印什么?
}
- 如果不是踩过坑的或者了解过的同学,一般会认为 不打印任何东西, 因为我的对象a,没有键值对。
- 看下打印结果
- 我们可以看到,
对象a是没有东西的,但是我们在Object的原型上添加了一个xiaom的方法,我们来看一下Object的原型都有什么东西。
- 我们可以看到唯一的区别便是
xiaom的颜色比其他属性的颜色要重一点,但是这不是重点,重点是:属性描述符
自行写到原型上的方法,属性描述符默认是可被遍历的,而原生自带的原型方法的属性描述符设置的是不可被遍历的
什么是属性描述符?
在 JavaScript 中,对象的属性可以分为两种:
- 数据属性:它的本质就是一个数据
- 存取器属性:它的本质是一个函数,但是可以将它当作普通属性来使用,当给该属性赋值时,会运行相应的 setter 函数,当获取该属性的值时,会运行相应的 getter 函数。除了存取器,还有一些其他的关键字,用以表示当前属性是否可写、是否有默认值、是否可枚举等,这些关键字就是属性描述符。
属性描述符是 ECMAScript5 新增的语法,它其实就是一个内部对象,用来描述对象的属性的特性.
描述符 有哪几种呢?
-
enumerable: 当且仅当该属性的enumerable键值为true时,该属性才会出现在对象的枚举属性中。 默认为false。 -
configurable: 当且仅当该属性的configurable键值为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为false。 -
value: 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 **默认为undefined -
writable: 当且仅当该属性的writable键值为true时,属性的值,也就是上面的value,才能被[赋值运算符]改变。 默认为false -
get: 属性的 getter 函数,如果没有 getter,则为undefined。 -
set: 属性的 setter 函数,如果没有 setter,则为undefined。
如何查看当前对象的属性描述符
Object.getOwnPropertyDescriptors
举个例子
我们通过Object.defineProperty 设置该对象的xiaom属性为不可枚举时,我们在for in 的时候已经循环不出来这个key了。但是并不影响我们使用
总结
在使用for in 遍历对象时 注意以下几点:
- 如果不想遍历原型上面的方法,加个判断
Object.hasOwnProperty(key) - for in 在遍历数组时,key是下标 而且是
string类型的 下标 且是 无序的 - 如果迭代的对象的变量值是null或者undefined, for... in不执行循环体,建议在使用for... in循环之前,先检查该对象的值是不是null或者undefined
- for in 一般用于可枚举的数据中,即 数组,对象, 字符串