判断一个值为字面量对象

967 阅读2分钟

博客原地址 欢迎交流,欢迎star

之前在阅读梳理分析redux源码的时候,在combineReducers函数里面看到了redux自己写判断一个值是否为字面量对象,为啥要有这样一个函数呢?是因为redux的中的action必须要是一个字面量对象。在此,顺便看了一下实现,然后搜索了一下网上的一些介绍,所以在这里整理分享一下。

isPlainObject

js的一些技术文章中,经常有听到或者看到说字面量对象。对于一个字面对象来说,它的原型就应该直接为js对象中原型的最源头Object.prototype。根据这一特性就比较容易来书写这份代码了。看看redux中的实现:

export default function isPlainObject(obj) {
  if (typeof obj !== 'object' || obj === null) return false

  let proto = obj
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }

  return Object.getPrototypeOf(obj) === proto
}
  1. 如果传入的不是object或者是一个null就会直接返回false
  2. 使用while循环拿到obj原型链上最后的那个对象。
  3. 通过Object.getPrototype获取obj的原型值和proto比较,如果相等则认为是字面量对象,为什么?因为如果相等的话,就代表这个对象原型链只有一层。上面说过,字面量对象的原型上只有一个Object.prototype
isPlainObject(Object.create(Object.prototype))
// true
isPlainObject({ a: 1 })
// true
isPlainObject(1)
// false
isPlainObject(() => {})
// false

Object.create(null)

对于Object.create(null)创建的对象,是没有原型的,那这种属于字面量对象吗?

Object.create(null)
如果我们这里需要判断这个没有原型的对象也是字面量的话,就需要在返回结果中添加一个条件了。

export default function isPlainObject(obj) {
  if (typeof obj !== 'object' || obj === null) return false

  let proto = obj
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }

  return Object.getPrototypeOf(obj) === proto || Object.getPrototypeOf(obj) === null
}

小结

网上还有其他isPlainObject的实现,有些代码还是很复杂的,边界条件考虑的很多。但是就如Object.create(null)创建的对象一样,就看真实的业务中是否需要做到如此细的判断。这个函数可以作为js原型链知识的一个补充。如有错误请指出,一起学习,谢谢。