在使用for in中,你可能遇到的问题

89 阅读3分钟

今天来深究一下for in 的背后都存在什么

先看一个小例子

1.思考一下下面的代码会输出什么?

   Object.prototype.xiaom = function () { console.log('前端老酒馆') }
   let a = {}
   for(let key in a) {
       console.log(key) // 打印什么?
   }
  1. 如果不是踩过坑的或者了解过的同学,一般会认为 不打印任何东西, 因为我的对象a,没有键值对。
  2. 看下打印结果

image.png

  1. 我们可以看到,对象a 是没有东西的,但是我们在 Object原型上添加了一个xiaom的方法,我们来看一下Object的原型都有什么东西。

image.png

  1. 我们可以看到唯一的区别便是 xiaom 的颜色比其他属性的颜色要重一点,但是这不是重点,重点是: 属性描述符

自行写到原型上的方法,属性描述符默认是可被遍历的,而原生自带的原型方法的属性描述符设置的是不可被遍历的

什么是属性描述符?

在 JavaScript 中,对象的属性可以分为两种:

  • 数据属性:它的本质就是一个数据
  • 存取器属性:它的本质是一个函数,但是可以将它当作普通属性来使用,当给该属性赋值时,会运行相应的 setter 函数,当获取该属性的值时,会运行相应的 getter 函数。除了存取器,还有一些其他的关键字,用以表示当前属性是否可写、是否有默认值、是否可枚举等,这些关键字就是属性描述符。

属性描述符是 ECMAScript5 新增的语法,它其实就是一个内部对象,用来描述对象的属性的特性.

描述符 有哪几种呢?

  1. enumerable : 当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false

  2. configurable: 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false

  3. value: 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 **默认为 undefined

  4. writable: 当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被[赋值运算符]改变。 默认为 false

  5. get: 属性的 getter 函数,如果没有 getter,则为 undefined

  6. set: 属性的 setter 函数,如果没有 setter,则为 undefined

如何查看当前对象的属性描述符

Object.getOwnPropertyDescriptors

举个例子

我们通过Object.defineProperty 设置该对象的xiaom属性为不可枚举时,我们在for in 的时候已经循环不出来这个key了。但是并不影响我们使用

image.png

总结

在使用for in 遍历对象时 注意以下几点:

  1. 如果不想遍历原型上面的方法,加个判断 Object.hasOwnProperty(key) image.png
  2. for in 在遍历数组时,key是下标 而且是 string 类型的 下标 且是 无序的
  3. 如果迭代的对象的变量值是null或者undefined, for... in不执行循环体,建议在使用for... in循环之前,先检查该对象的值是不是null或者undefined
  4. for in 一般用于可枚举的数据中,即 数组,对象, 字符串