Skip to content Skip to sidebar Skip to footer

The Implementation Of Isplainobject Function In Redux

Recently, I'm reading the source code of redux. But, I can't understand this code in isPlainObject function: /** * @param {any} obj The object to inspect. * @returns {boolean} Tr

Solution 1:

I think it works like the code return Object.getPrototypeOf(obj) === Object.prototype

Yes, that's the basic idea.

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

No, that is not what it checks for.

Could you explain?

A comparison for equality with Object.prototype only works for objects that actually inherit from Object.prototype. This is not always the case for plain objects though, which might come from another realm - like an iframe - and inherit from the other realm's Object.prototype. To detect these, the code basically first searches for an Object.prototype-like (i.e. inheriting from null) object in the prototype chain of the argument, and then checks whether the argument directly inherits from that.

Of course, the whole looping thing is quite unnecessary, they could (should) simplify to

exportdefaultfunctionisPlainObject(obj) {
  if (typeof obj !== 'object' || obj === null) returnfalseconst proto = Object.getPrototypeOf(obj);
  return proto !== null && Object.getPrototypeOf(proto) === null;
}

Solution 2:

As the name of the function states it looks for if an object is plain or not.

The plain objects in javascript are Objects created by {}, new Object() or Object.create(null). Here is a more detailed explanation of plain object https://www.quora.com/What-is-a-plainObject-in-JavaScript/answer/%E9%A3%9E-%E7%BD%97-1.

All we trying to do is looking for if the given object's prototype is equal to Object.prototype or it equals to null.

In code

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

In case you want to know why we have null check, when we create an object with Object.create(null) the prototype of it has a null value. In other words:

Object.getPrototypeOf(Object.create(null)) === null =>true

Now, if we could get the desired answer as easily as the above snippet, why they put a while loop that makes the understanding of the code harder? Of course, the only reason is not to make it harder :)

When we try to access variables across iframes, the prototype of the plain objects created in the file that imports the iframe and the framed file are not equal. This is because they run in separate environments. In other words, prototypes of the objects are still pointing to the Object constructors, but the Object constructors are not equal to each other.

To better understand, we can demo it. Create 4 files in the same folder: index.html frame.html index.js frame.js.

Note: To make the below example work without browsers block cross-origin frames, you should put them in a local server. Or just use vscode Live Server extension

Below index.html imports frame.html as iframe. It also imports index.js which only contains a global variable plainObject. Also, frame.html only imports frame.js.

In frame.js we reach the plainObject variable as window.parent.plainObject. Here plainObject lives in the context of index.html and index.js and as we see in the second line console.log statement: the prototype of window.parent.plainObject is not equal to Object.prototype of frame.js context.

It is exactly why redux implemented the function with a while loop. In frame.js, from line 3 to line 5 we have the same while loop as redux have. After that loop we can safely check if the plainObject of parent is a plain object or not by looking if there is any other proto constructor between it and getPrototype result of it. The console.log statement in line 6 checks it.

The content of each file:

index.html:

<!DOCTYPE html><body><scriptsrc="./index.js"></script><iframesrc="frame.html"></body></html>`

frame.html:

<!DOCTYPE html><body><scriptsrc='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 environmentwhile(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

Post a Comment for "The Implementation Of Isplainobject Function In Redux"