JSON.parse不会在循环对象上出错 [英] JSON.parse not erroring on cyclic objects

查看:210
本文介绍了JSON.parse不会在循环对象上出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图确定一个对象是否可以字符串化。此检查适用于Chrome和Safari,但不适用于FF(25.0.1)。

  var good = true; 
var myObj = {param1:11,param2:a string,param3:$(a)};
//一些循环对象,特别是我有一个jQuery对象,我通过`$(a)`
// //返回了几个锚标签。

//尝试字符串化,据推测会拒绝循环对象
try {
JSON.stringify(myObj);
} catch(error){
good = false;
}
console.log(good)//返回true。

没有错误发生,或者我没有正确地捕捉到它?我以前从来没有打过电话来尝试使用try ... catch,所以我对它的细微差别的经验是空的。



JSON.stringify myObj)返回一个字符串版本的对象,sans许多对象参数显然不能字符串化。它应该根据 MDN ,错误。



谢谢!

解决方案

您正确地捕捉错误,但是(如您所识别的) Firefox只是不会抛出一个错误。

这是因为Fiefox不会窒息DOM对象的JSON化,在其他浏览器中这样做:

  JSON.stringify(document.getElementById(header))

在Chrome和Safari中,这一行会导致错误(因为在WebKit / Blink中,像兄弟姐妹一样的循环DOM对象直接存在于每个DOM对象上),而在Firefox中则无害地生成字符串

这是因为Firefox的DOM对象没有任何自己的枚举属性:

{} >

  Object.keys(document.getElementById(header))
>在WebKit / Blink浏览器中,这一行提供了一个属性名称的字符串数组,因为DOM对象有自己的属性。 JSON.stringify 只会捕获一个对象自己的属性,而不是原型属性。
$ b

奖金信息:超过你想要的了解DOM



在Firefox中,DOM对象大多没有自己的属性;相反,属性访问是通过原型链委托给 HTMLElement.prototype Element.prototype Node.prototype (或元素的直接原型,如 HTMLDivElement.prototype HTMLAnchorElement.prototype



这里的技巧是原型属性没有,它们是 getter 函数。例如,当您询问 HTMLDivElement firstChild 时,JavaScript引擎会执行以下步骤:


  1. 查找对象本身的 firstChild 属性。它不在那里。
  2. 在对象原型上查找 firstChild 属性。

  3. 继续直到我们在 Node.prototype 上找到 firstChild

  4. Node.prototype.firstChild 是由访问器属性描述符定义的,这意味着属性访问导致执行 get

  5. 执行getter函数时, this 值是特定的DOM元素,其 firstChild 您要求的值/ Firefox使用这个值来进行DOM元素的第一个引擎

因此,当您这样做时:

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

你确实在做:

  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); //将`this`设置为`elm`来调用getter

或者(更少可读):

  var val = Object.getOwnPropertyDescriptor(document.getElementById(header).__ proto __.__ proto __.__ proto __.__ proto__,firstChild ).get.call(document.getElementById(header))


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!

解决方案

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"))

这篇关于JSON.parse不会在循环对象上出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆