开头一个问题是:什么是 Plain Object
?
并没有看到有官方去专门定义它,更可能它只不过是业界的一种通俗叫法,因此也没有严格的定义。但我们在汉语环境里通常叫它“纯对象”。
业界解释:https://www.quora.com/What-is-a-plainObject-in-JavaScript
下面我们来看一下常见 Library 对 isPlainObject 函数的实现。
jQuery jQuery 3.3 版本中的 isPlainObject 定义在这里 。
为便于阅读,核心代码经过整理后如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function isPlainObject (obj ) { var proto, Ctor ; if (!obj || ({}).toString .call (obj) !== "[object Object]" ) { return false ; } proto = Object .getPrototypeOf (obj); if (!proto) { return true ; } Ctor = ({}).hasOwnProperty .call (proto, "constructor" ) && proto.constructor ; return typeof Ctor === "function" && Function .prototype .toString .call (Ctor ) === Function .prototype .toString .call (Object ); }
lodash lodash 4.0.6 版本中的 isPlainObject 定义在这里 。
基本与 jQuery 版本相同,多了一个 Ctor instanceof Ctor 的条件,满足此条件的仅有 Function 和 Object 两个函数。
1 2 3 4 5 6 7 8 9 10 11 function isPlainObject (value ) { if (!value || typeof value !== 'object' || ({}).toString .call (value) != '[object Object]' ) { return false ; } var proto = Object .getPrototypeOf (value); if (proto === null ) { return true ; } var Ctor = hasOwnProperty.call (proto, 'constructor' ) && proto.constructor ; return typeof Ctor == 'function' && Ctor instanceof Ctor && Function .prototype .toString .call (Ctor ) === Function .prototype .toString .call (Object ); }
redux redux 从 4.0.0 开始在测试中使用了 isPlainObject ,代码在这里 。
它的实现比较简单。
1 2 3 4 5 6 7 8 9 10 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 }
我们并没有一个能判断 Plain Object 的清晰逻辑,大概能理出来的思路是:
先判断 obj 本身是否满足我们熟悉的合法对象概念;
判断 obj 的构造函数是不是 Object
至于判断 prototype 是不是 null,无非是一种 shortcut 罢了。