我正在尝试确定对象是否可以字符串化。此检查在Chrome和Safari中有效,但在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.
没有抛出错误…还是我没有正确捕获它?在此之前,我从未打电话给过使用try … catch的经历,所以我对其细微差别的经验是空的。
JSON.stringify(myObj)返回对象的字符串版本,没有许多对象参数,这些参数显然无法进行字符串化。根据MDN,它应该出错。
JSON.stringify(myObj)
谢谢!
您正在正确地捕获错误,但是(正如您所确定的)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仅捕获对象自身的属性,而不捕获原型属性。
JSON.stringify
在Firefox中,DOM对象通常不具有自己的属性。相反,属性访问被委派了原型链的HTMLElement.prototype,Element.prototype或者Node.prototype(或元素的直接原型,像HTMLDivElement.prototype或HTMLAnchorElement.prototype)。
HTMLElement.prototype
Element.prototype
Node.prototype
HTMLDivElement.prototype
HTMLAnchorElement.prototype
您可能想知道: 如果访问DOM元素上的属性导致原型访问,那么DOM元素如何具有不同的属性值? 并非所有DOM元素都具有或多或少相同的原型链吗?
这里的技巧是原型属性没有 值 ,它们是 getter 函数。例如,当您要求输入firstChild时HTMLDivElement,JavaScript引擎执行以下步骤:
firstChild
HTMLDivElement
Node.prototype.firstChild
get
this
因此,当您这样做时:
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); // invoke the getter with `this` set to `elm`
或(不太可读):
var val = Object.getOwnPropertyDescriptor(document.getElementById("header").__proto__.__proto__.__proto__.__proto__, "firstChild").get.call(document.getElementById("header"))