for...in为什么需要hasOwnProperty判断?

395 阅读2分钟

我们经常使用for...in 循环对象输出键和值

如:

const obj = {a: 1, b: 2}
for(let key in obj) {
  console.log(key) // => a b
  console.log(obj[key]) // => 1 2
}

但在某些编辑器(如vscode)中输入forin,会自动生成如下代码:

for (const key in object) {
  if (Object.hasOwnProperty.call(object, key)) {
    const element = object[key];
    // todo ..
  }
}

每次都会想这句

(Object.hasOwnProperty.call(object, key)

是不是多余的呢?

引用MDN解释,for...in语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。

重点:包括继承的可枚举属性

下面看一个例子:

function School() {
  this.school = '南翔'
}

function Person () {
  this.name = '小明'
  this.age = '18'
}

Person.prototype = new School()

var p = new Person()

// 我们要打印p上面的属性
for(let key in p) {
  console.log(`${key} = ${p[key]}`)
}
// 输出
// name = 小明
// age = 18
// school = 南翔

Person.prototype = new School()

Person的原型上继承了School,输出了school = 南翔,这里不明白的话建议看看你红宝书继承那一章,这里简单使用,不做解释!

我们的目标是输出p自己的属性,明显这不符合如期,所以hasOwnProperty派上用场了

引用MDN解释:

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)

// ..省略
for(let key in p) {
  if(Object.hasOwnProperty.call(p. key)) {
    console.log(`${key} = ${p[key]}`)
  }  
}
// 输出
// name = 小明
// age = 18

当然,小伙伴工作时候一般遍历let obj = {}这种对象,其实可以省略,但是如果我们开发一些工具库的时候还是严谨点好。

延伸问题:

Object.hasOwnProperty.call(p. key)

hasOwnProperty是Object上的方法,所有对象默认会继承该方法,为什么不直接

p.hasOwnProperty(key)

而使用

Object.hasOwnProperty.call(object, key)

我们试试:

// ..省略
for(let key in p) {
  if(p.hasOwnProperty(key)) {
    console.log(`${key} = ${p[key]}`)
  }  
}
// 输出
// name = 小明
// age = 18

好明显是符合如期的!

为啥要这么写呢,那肯定有它的原因!!!

假设我们把代码改一下:

// ..其他省略
function Person () {
  this.name = '小明'
  this.age = '18'
  this.hasOwnProperty = function() {
    return false
  }
}
for(let key in p) {
  if(p.hasOwnProperty(key)) {
    console.log(`${key} = ${p[key]}`)
  }  
}
// 输出 ??? 啥也没有

好明显,我们定义hasOwnProperty把原来的方法覆盖了,虽然我们平时不会这样做,但还是那句话,如果我们开发工具或者库得时候,写代码还是得严谨点好!

完结