我最近在阅读和比较某些[[Class]]
属性的值时遇到了IE8的问题(此时我还不知道9)。实际上只有localStorage
对象的情况才会出现。
我正在使用像这样的方法
var ToStr = Object.prototype.toString;
Object.type = function _type( obj ) {
var res = ToStr.call( obj ).split( ' ' )[ 1 ].replace( ']', '' );
if( obj === window ) {
res = 'Window';
}
else if( res === 'Window' || res === 'Global' ) {
res = 'Undefined';
}
else if( res.indexOf( 'HTML' ) === 0 ) {
res = 'Node';
}
return ( res );
};
此方法将返回此值,例如:
var foo = { },
bar = [ ],
num = 52,
win = window;
Object.type( foo ) === 'Object'; // true
Object.type( bar ) === 'Array'; // true
Object.type( num ) === 'Number'; // true
Object.type( win ) === 'Window'; // true
当然,在我所知道的所有浏览器中,只需从对象本身检查[[Class]]
属性即可。现在,我在localStorage
对象
Object.type( win.localStorage ) === 'Storage' // true (not in IE8)
IE8只返回Object
。但是,这不是实际问题,当您尝试将localStorage
对象与window
对象进行比较时,会出现问题。如您所见,我正在检查传入的参数是否是当前的window
对象
if( obj === window ) { }
如果obj
现在是window.localStorage
对象,则会出现错误
"Class does not support automation"
只有在您尝试将localStorage
与window
进行比较时才会发生这种情况,您可以将其与其他任何内容进行比较而不会有任何问题。这只是另一个错误,还是我能以某种方式解决这个问题?
我想基本上我的问题是:
如果你正在处理localStorage
对象,你怎么知道IE8(也可能是IE9)?
我要做的最后一件事是用try-catch
内部包装整个方法,因为它经常被调用。
完全让我感到困惑的是:当你在IE8的控制台中执行console.log( obj )
时,它会返回[object Storage]
(很好!)但是如果你调用Object.prototype.toString.call( obj )
它会返回[object Object]
}。同样适用于typeof obj
,将返回object
。
第二个问题:
IE8 console
如何打印出正确的[[Class]]
?
答案 0 :(得分:6)
我找到了一种使用隐式toString()
操作解决IE8行为的方法,ECMAScript规范解释了为什么解决方法有意义。隐含的toString()
就是这样:
"" + window.localStorage
这隐含地强制调用对象的内部toString()
方法,并且在IE中,这将返回您想要的[object Storage]
所需的表单,并且您可以使代码无需工作特殊套管window.localStorage
。
所以,我一直在寻找将其融入现有代码的最小风险方式。选择的方法是获取与您使用相同方式获取它的类型,当且仅当它返回泛型" Object"键入,然后查看新方法是否有更好的名称。所以,过去工作得很好的所有东西都将继续以他们的方式工作,我们可能会找到一些更好的名称,用于返回通用"对象"的某些对象(如window.localStorage
)。名称。另一个变化是我对从"" + obj
构造得到的确切返回类型感到不太自信,所以我想要一个不会在意外数据上抛出错误的解析方法,所以我切换到了来自您使用的拆分/替换方法的正则表达式。正则表达式也强制它实际上也是[object Type]
格式,这似乎是可取的。
然后,为了防止比较localStorage === window
和获取错误的奇怪问题,您可以添加类型检查(鸭子类型)非类似窗口的对象不会通过,这将过滤掉{ {1}}问题和具有相同问题的任何其他对象。在这种特殊情况下,我确保对象的类型为localStorage
,并且它具有名为"object"
的属性。我们可以选择setInterval
对象的任何众所周知的,支持良好的属性,该属性不可能出现在任何其他对象上。在这种情况下,我使用window
,因为它与jQuery在想知道对象是否是窗口时使用的测试相同。注意,我还将代码更改为未明确与setInterval
进行比较,因为可能有多个window
对象(框架,iframe,弹出窗口等等),所以这样,它会返回" Window"对于任何窗口对象。
以下是代码:
window
在此处查看包含各种测试用例的演示:http://jsfiddle.net/jfriend00/euBWV
您为了解析"存储"所需的Object.type = function _type( obj ) {
function parseType(str) {
var split = str.split(" ");
if (split.length > 1) {
return(split[1].slice(0, -1));
}
return("");
}
var res = parseType(Object.prototype.toString.call(obj));
// if type is generic, see if we can get a better name
if (res === "Object") {
res = parseType("" + obj);
if (!res) {
res = "Object";
}
}
// protect against errors when comparing some objects vs. the window object
if(typeof obj === "object" && "setInterval" in obj) {
res = 'Window';
}
else if( res === 'Window' || res === 'Global' ) {
res = 'Undefined';
}
else if( res.indexOf( 'HTML' ) === 0 ) {
res = 'Node';
}
return ( res );
};
值。类名来自ECMAScript spec中定义的内部"[object Storage]"
属性。在8.6.2节中,规范定义了[[Class]]
的特定类名。它没有为"Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String"
这样的主机对象定义类名,因此可以将其留给单个浏览器,也可以在其他规范文档中找到。
此外,规范说明了localStorage
:
[[Class]]内部属性的值在内部使用 区分不同种类的物体。注意这个规范 没有为程序提供任何访问该值的方法,除非 通过Object.prototype.toString(见15.2.4.2)。
并且,在15.2.4.2中,我们通过使用[[Class]]
作为第二个单词找到了生成类似[object Array]
或[object String]
的输出的规范。
所以,[[Class]
是应该如何工作的。显然,IE8在这方面存在对Object.prototype.toString
对象的错误。我们无法在IE8内部了解localStorage
是否未使用toString()
或[[Class]]
未正确设置。在任何情况下,IE8中的[[Class]]
似乎都没有直接使用console.log()
,因为它会产生不同的结果。
Object.prototype.toString()
解决方法的行为更加难以理解。该规范描述了如何将对象的类型强制转换为字符串。在整个规范中一直遵循线程有点复杂,因为一部分依赖于另一部分依赖于另一部分,依此类推。但是,最后,它执行内部方法"" + obj
,显然在IE8中ToString(ToPrimitive(input argument, hint String))
,当传递一个提示,我们想要一个字符串给我们ToPrimitive
不是的实际类名。有一条通过Object.prototype.toString()
的规范的路径,这可能是IE8中发生的情况,但是因为我们已经知道IE8没有遵循规范的第一部分而且一般都没有不管怎样,擅长遵循规范,假设它遵循这方面的规范并不是一个有效的假设。最后,我们只知道在IE8中对字符串进行类型强制最终会向我们提供我们想要的[[DefaultValue]]
。
作为一项有趣的测试,我在Chrome浏览器中尝试了我的测试套件,通过[[Class]]
解决方案运行作为对象的所有测试用例(通常代码仅在"" + obj
无法使用时使用该路径#39; t返回Object.prototype.toString()
以外的名称。它适用于除数组之外的所有内容。我认为这意味着对象的"Object"
通常为[[DefaultValue]]
(除非对象类型决定它有一个更好的默认值[[Class]]
显然是这样做的。所以,我认为我们已经确认修复IE8的解决方案实际上应该按照规范工作。因此,它不仅是一个解决方案IE8,但如果对象类型没有实现不同的默认值,它是获取Array
名称的替代路径。
所以,我通过规范提出的新代码真的是这个伪代码:
[[Class]]
[[Class]]
Object.prototype.toString()
以外的其他内容,请使用"Object"
尝试获取"" + obj
[[DefaultValue]]
更有用的东西,那么只需返回"Object"
答案 1 :(得分:3)
您写道:
只有在您尝试将
localStorage
与window
进行比较时才会发生这种情况,您可以毫不费力地将其与其他任何内容进行比较。
那你为什么不这样做?
var ToStr = Object.prototype.toString;
Object.type = function _type( obj ) {
if ( window.localStorage && obj === window.localStorage )
return 'Storage';
if ( obj === window )
return 'Window';
var res = ToStr.call( obj ).split( ' ' )[ 1 ].replace( ']', '' );
if ( res === 'Window' || res === 'Global' ) {
return 'Undefined';
if ( res.indexOf( 'HTML' ) === 0 ) {
return 'Node';
return res;
};
除了直接回答问题外:
obj === window.localStorage
即可查看。它不能比那更简单,可以吗?此致 斯特芬
答案 2 :(得分:1)
应使用功能检测(见下文),以避免尝试访问失败localStorage
due to browser policies etc.
至于IE8特定的问题,您是否可以确认该网页正在提供而不是在本地打开?即URL为http://localhost/hello.html
而不是file:///C:/somefolder/hello.html
IE8不允许localStorage
本地打开的文件,但是没有找到官方文档来支持这个(但是this和this :)另外,可能值得检查一下你是不是在IE7模式下运行浏览器。
如果上面的代码应该检测到功能可用性而不是其他东西,那么可以选择使用the following之类的代码:
// Feature test
var hasStorage = (function() {
try {
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
}());
答案 3 :(得分:0)
这根本不是很好。我能获得字符串"[object Storage]"
的唯一方法是使用以下代码:
obj.constructor.toString();
对于任何本机构造函数,其他浏览器中的输出和预期输出是本机函数的字符串表示形式。但是,我们在这里讨论的是主机对象,其中完全适用不同的规则。有趣的是,尽管对DOM进行了所有改进,IE 9也给出了相同的结果。
这不是一个完全有弹性的解决方案,但它是我能在短时间内找到解决问题的唯一解决方案。
似乎IE 8和IE 9的IE 8文档模式之间存在差异,localStorage.constructor
实际上并不存在于前者中。在这种情况下,我认为没有另一种可行的解决方案。鸭子打字似乎不会有效,因为所有localStorage
对象的属性名称都是通用的。你可以使用
window.localStorage === obj
但是当我试图覆盖窗口对象的本机属性时,我不确定IE 8的行为(如果它不允许它,那么你可能没问题。)
答案 4 :(得分:0)
这确实是一个非常奇怪的IE8
错误! (哦,我喜欢IE浏览器)!
正如IE8
浏览器的评论中所述,我认为只有一种解决方案:
typeof obj === "object" && obj.constructor.toString() === "[object Storage]"
确保当前浏览器在检查之前是IE8,否则不工作,甚至在其他版本的IE中也不行!
P.S。 IE与其兄弟姐妹的兼容性的一个很好的例子!