Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

javascript - JSON.parse not erroring on cyclic objects

I'm trying to determine if an object can be stringified or not. This check works in Chrome and Safari, but not in FF (25.0.1).

var good = true;
var myObj = {"param1":11, "param2": "a string", "param3": $("a")}; 
//some cyclic object, specifically I have a jQuery object I got via `$("a")` 
//which returned several anchor tags.

//try to stringify, which supposedly rejects cyclic objects 
try {
    JSON.stringify(myObj);
} catch(error){
    good = false;
}
console.log(good) //returns true.

No error thrown... or I'm not catching it properly? I've never had call to use try... catch before now, so my experience with its nuances is null.

JSON.stringify(myObj) returns a string version of the object, sans many of the object parameters which obviously can't be stringified. It should, according to MDN, error.

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You're catching the error properly, but (as you've identified) Firefox simply isn't throwing an error.

This is because Fiefox doesn't choke on JSONification of DOM objects, where other browsers do:

JSON.stringify(document.getElementById("header"))

In Chrome and Safari, this line results in an error (because in WebKit/Blink, cyclic DOM objects like siblings exist directly on each DOM object), while in Firefox with harmlessly produces the string "{}".

This is because Firefox's DOM objects do not have any of their own enumerable properties:

Object.keys(document.getElementById("header"))
> []

In WebKit/Blink browsers, this line provides an array of property names as strings, because DOM object have their own properties. JSON.stringify only captures an object's own properties, rather than prototype properties.

Bonus Info: More Than You Wanted to Know About the DOM

In Firefox, DOM objects mostly don't have their own properties; instead, property access is delegated up the prototype chain to the HTMLElement.prototype, Element.prototype, or Node.prototype (or the element's immediate prototype, like HTMLDivElement.prototype or HTMLAnchorElement.prototype).

You might wonder: if accessing a property on a DOM element results in prototype access, how can DOM elements have different property values? Don't all DOM elements have more or less the same prototype chain?

The trick here is that the prototype properties don't have values, they are getter functions. For example, when you ask for firstChild of a HTMLDivElement, the JavaScript engine takes the following steps:

  1. Look for the firstChild property on the object itself. It's not there.
  2. Look for the firstChild property on the object's prototype.
  3. Continue up the prototype chain until we find firstChild on Node.prototype.
  4. Node.prototype.firstChild is defined by an accessor property descriptor, meaning that property access results in the execution of a get function.
  5. The this value during the execution of the getter function is the particular DOM element whose firstChild value you asked for/ Firefox uses that this value to do some under-the-hood lookup of the DOM element's first child.

Thus, when you do:

var val = document.getElementById("header").firstChild;

you're really doing:

var elm = document.getElementById("header");
var nodeProto = elm.__proto__.__proto__.__proto__.__proto__;
var propDescriptor = Object.getOwnPropertyDescriptor(nodeProto, "firstChild");
var getterFunc = propDescriptor.get;
var val = getterFunc.call(elm);  // invoke the getter with `this` set to `elm`

Or (less readably):

var val = Object.getOwnPropertyDescriptor(document.getElementById("header").__proto__.__proto__.__proto__.__proto__, "firstChild").get.call(document.getElementById("header"))

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...