isPlainObject
函数是redux
自己用来判断传递给reducer
的action
对象是一个plain object
,也就是通过字面量方式或者Object
构造函数的方式生成的对象,中间没有发生其他的继承情况,保持action
对象是一个plain object
的作用是,方便reducer
进行处理,不用处理其他的情况(例如:promise/function/class实例
等等),另一方面,也是方便的对状态进行记录或者回溯(比如说redux devtool
工具里的action
删除、跳过等操作)
/**
* @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
}
代码理解也不难,就是通过一个while循环拿到参数对象原型链的最后一个值,普通的对象while循环结束后proto
的值是:Object.prototype
,通过Object.create(null)
生成的对象proto
的值是:null
但是为什么不直接进行下面的判断呢?
return Object.getPrototypeOf(obj) === Object.prototype || Object.getPrototypeOf(obj) === null
这段代码仿佛和redux
code的作用是一样的,我最开始也是不太理解,查看了官方github仓库下面的讨论后才了解到原因~~
redux
的代码是为了防止一些边界情况的出现,对于一些cross-realm
情况(例如跨frame访问变量时),使用我的代码就可能出现问题,比如说在一个frame里面调用父窗口的函数:
window.parent.someFunction(["hello", "world"])
在父窗口中有someFunction的定义:
function someFunction(arg) {
if (arg instanceof Array) {
// ... operate on the array
}
}
这样调用并不会执行if
语句的代码,因为两段代码所处的javascript
执行环境是不一样的,每个frame
都有自己的执行环境,他们也不会共享原型链,也就是说两个执行环境中的Array
Object
构造函数都是不等的,那么if
语句的判断就为false
,这个数组并不是继承的父窗口执行环境里的Array
。
这种情况下使用我的代码进行plain object
判断自然也会出现问题。像其他的一些情况,例如不同的window
窗口都算是处于不同的javascript
执行环境~~
发现错误请留言告诉我~~~