Javascript 在redux中实现isPlainObject函数

Javascript 在redux中实现isPlainObject函数,javascript,redux,Javascript,Redux,最近,我正在阅读redux的源代码。但是,我无法理解此代码的功能: /** * @param {any} obj The object to inspect. * @returns {boolean} True if the argument appears to be a plain object. */ export default function isPlainObject(obj) { if (typeof obj !== 'object' || obj === null)

最近,我正在阅读redux的源代码。但是,我无法理解此代码的功能:

/**
 * @param {any} obj The object to inspect.
 * @returns {boolean} True if the argument appears to be a plain object.
 */
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
}
我想它的工作原理和下面的代码一样,你能给我解释一下吗

return Object.getPrototypeOf(obj) === Object.prototype || Object.getPrototypeOf(obj) === null
我认为它的工作原理类似于代码
returnobject.getPrototypeOf(obj)==Object.prototype

是的,这是基本的想法

…|| Object.getPrototypeOf(obj)==null

不,这不是它检查的内容

你能解释一下吗

Object.prototype
相等的比较仅适用于实际继承自
Object.prototype
的对象。不过,普通对象并不总是这样,它可能来自另一个领域(如iframe),并从另一个领域的
对象.prototype
继承。要检测这些,代码基本上首先在参数的原型链中搜索
对象.prototype
-like(即继承自
null
)对象,然后检查参数是否直接继承自该对象

当然,整个循环过程是完全不必要的,它们可以(应该)简化为

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

  const proto = Object.getPrototypeOf(obj);
  return proto !== null && Object.getPrototypeOf(proto) === null;
}

正如函数名所述,它查找对象是否为普通对象

javascript中的普通对象是由{}、new Object()或Object.create(null)创建的对象。下面是对普通对象的更详细解释

我们要做的就是寻找给定对象的原型是否等于
object.prototype
,或者它是否等于
null

编码

Object.getPrototypeOf(obj) === Object.prototype || Object.getPrototypeOf(obj) === null
如果你想知道为什么我们要进行空检查,当我们用
object.create(null)
它有一个空值。换言之:

Object.getPrototypeOf(Object.create(null)) === null => true
现在,如果我们可以像上面的代码片段一样容易地得到想要的答案,为什么他们会设置一个while循环,使理解代码变得更加困难?当然,唯一的原因不是让事情变得更难:)

当我们试图跨iframe访问变量时,在导入iframe的文件中创建的普通对象的原型与框架文件不相等。这是因为它们在不同的环境中运行。换句话说,对象的原型仍然指向对象构造函数,但对象构造函数彼此不相等

为了更好地理解,我们可以演示它。在同一文件夹中创建4个文件:index.html frame.html index.js frame.js

注意:要使下面的示例在浏览器不阻止跨原点帧的情况下工作,您应该将它们放在本地服务器中。或者只使用vscode实时服务器扩展

下面index.html将frame.html作为iframe导入。它还导入index.js,它只包含一个全局变量
plainObject
。此外,frame.html仅导入frame.js

在frame.js中,我们将
plainObject
变量作为
window.parent.plainObject
。这里
plainObject
存在于index.html和index.js的上下文中,正如我们在第二行
console.log
语句中看到的那样:
window.parent.plainObject
的原型不等于frame.js上下文的
Object.prototype

这正是redux使用while循环实现函数的原因。在frame.js中,从第3行到第5行,我们有与redux相同的while循环。在这个循环之后,我们可以通过查看父对象的
plainObject
和它的getPrototype结果之间是否存在任何其他原型构造函数来安全地检查它是否是一个普通对象。第6行中的console.log语句检查它

每个文件的内容:

index.html:

<!DOCTYPE html>
  <body>
    <script src="./index.js"></script>
    <iframe src="frame.html">
  </body>
</html>`
frame.js

let parentPlainObject = window.parent.plainObject;

console.log(Object.getPrototypeOf(parentPlainObject) === Object.prototype) // this is equal to false because parentPlainObject's prototype is in another environment

while(Object.getPrototypeOf(parentPlainObject) !== null) {
  parentPlainObject = Object.getPrototypeOf(parentPlainObject)
}

console.log(parentPlainObject === Object.getPrototypeOf(window.parent.plainObject)) // now we can test if parentPlainObject is a plain one or has another proto constructor in prototype chain

需要注意的是,您的测试通过了redux为
isPlainObject
设置的所有测试,除非
obj
null
未定义
,如果您查看文件的历史记录,您会发现一些有用的详细信息,说明更改的原因:嗯,我的意思是,我的测试替换了代码:`let proto=obj….return Object.getPrototypeOf…`我几乎理解了它的作用。仅针对一些边缘情况(跨iframe、跨领域)。谢谢~~有关此特定实现背后的原因,请参阅中的讨论。@markerikson感谢您的确认!但仍然无法解释他们为什么使用循环:-)你必须直接询问Tim,但我模糊的假设是,这是为了确保我们真正处理的是根原型,而不是可能正在进行的任何潜在子类化。
var plainObject = {}
let parentPlainObject = window.parent.plainObject;

console.log(Object.getPrototypeOf(parentPlainObject) === Object.prototype) // this is equal to false because parentPlainObject's prototype is in another environment

while(Object.getPrototypeOf(parentPlainObject) !== null) {
  parentPlainObject = Object.getPrototypeOf(parentPlainObject)
}

console.log(parentPlainObject === Object.getPrototypeOf(window.parent.plainObject)) // now we can test if parentPlainObject is a plain one or has another proto constructor in prototype chain