最近,我正在阅读redux的源代码。但是,我无法在isPlainObject函数中理解此代码:
/**
* @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
答案 0 :(得分:1)
我认为它的工作原理类似于代码
return Object.getPrototypeOf(obj) === Object.prototype
是的,这是基本思想。
… || Object.getPrototypeOf(obj) === null
不,它不是要检查的内容。
你能解释吗?
与Object.prototype
的相等性比较仅适用于实际上从Object.prototype
继承的对象。但是,对于普通对象而言,情况并非总是如此,它可能来自另一个领域(例如iframe)并继承自另一个领域的Object.prototype
。为了检测到这些,代码基本上首先在参数的原型链中搜索类似Object.prototype
的对象(即从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;
}
答案 1 :(得分:0)
正如函数名称所述,它查找对象是否为普通对象。
javascript 中的普通对象是由 {}、new Object() 或 Object.create(null) 创建的对象。这里是对普通对象 https://www.quora.com/What-is-a-plainObject-in-JavaScript/answer/%E9%A3%9E-%E7%BD%97-1 的更详细解释。
我们要做的就是寻找给定对象的原型是否等于 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 的文件和框架文件中创建的普通对象的原型并不相等。这是因为它们在不同的环境中运行。换句话说,对象的原型仍然指向Object构造函数,但Object构造函数并不相等。
为了更好的理解,我们可以演示一下。在同一个文件夹中创建4个文件:index.html frame.html index.js frame.js.
注意:要使下面的示例在没有浏览器阻止跨源框架的情况下工作,您应该将它们放在本地服务器中。或者直接使用 vscode Live Server 扩展
在 index.html 下面将 frame.html 导入为 iframe。它还导入仅包含全局变量 plainObject
的 index.js。另外,frame.html 只导入 frame.js。
在 frame.js 中,我们将 plainObject
变量设为 window.parent.plainObject
。这里 plainObject
存在于 index.html 和 index.js 的上下文中,正如我们在第二行 console.log
语句中看到的:window.parent.plainObject
的原型不等于 Object.prototype
frame.js 上下文。
这正是 redux 使用 while 循环实现该功能的原因。在 frame.js 中,从第 3 行到第 5 行,我们有与 redux 相同的 while 循环。在该循环之后,我们可以通过查看它和它的 getPrototype 结果之间是否存在任何其他 proto 构造函数来安全地检查 parent 的 plainObject
是否是一个普通对象。第 6 行中的 console.log 语句会检查它。
每个文件的内容:
index.html:
<!DOCTYPE html>
<body>
<script src="./index.js"></script>
<iframe src="frame.html">
</body>
</html>`
frame.html:
<!DOCTYPE html>
<body>
<script src='frame.js'></script>
</body>
</html>
index.js
var plainObject = {}
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