奇怪的 IE8 内部 [[ class ]] 属性行为

2023-12-28

我最近在使用 IE8(目前我不知道 9)时遇到了一些麻烦,无法读取和比较某些值[[Class]]特性。事实上,这仅适用于以下情况localStorage object.

我正在使用这样的方法

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

Object.type( win.localStorage ) === 'Storage' // true (not in IE8)

IE8刚刚回归Object这里。然而,这不是真正的问题,当你尝试比较localStorage对象与window目的。正如你所看到的,我正在检查传入的参数是否是当前的window object

if( obj === window ) { }

If obj现在是window.localStorage对象,这将导致错误

"Class does not support automation"

仅当您尝试比较时才会发生这种情况localStorage with window,您可以毫无困难地将它与其他任何东西进行比较。这只是另一个错误还是我可以以某种方式解决这个问题?

我想基本上我的问题是:

你怎么知道在 IE8(也可能是 IE9)中你是否正在处理localStorage object?

我想做的最后一件事是用一个内部包装整个方法try-catch因为它经常被调用。

让我完全困惑的是:当你做一个console.log( obj )在 IE8 的控制台中它返回你[object Storage](很好!)但是如果你打电话Object.prototype.toString.call( obj )它返回[object Object]。同样适用于typeof obj, 将返回object.

第二个问题:

IE8如何console打印出正确的[[Class]] ?


我找到了一种使用隐式方法来解决 IE8 行为的方法toString()操作和 ECMAScript 规范解释了为什么该解决方法是有意义的。隐含的toString()这是:

"" + window.localStorage

这是隐式强制调用对象的内部toString()方法,在 IE 中,这将返回您想要的形式[object Storage]你可以让你的代码在没有特殊外壳的情况下工作window.localStorage.

因此,我一直在寻找风险最小的方法来将其合并到现有代码中。选择的方法是以与获取类型相同的方式获取类型,并且当且仅当它返回通用“对象”类型时,然后查看新方法是否有更好的名称可用。因此,所有过去工作得很好的东西都将继续像以前那样工作,我们可能会为某些对象找到更好的名称(例如window.localStorage)用于返回通用“对象”名称。另一个变化是,我对我们可能从该项目中获得的确切回报类型不太有信心。"" + obj因此我想要一种不会对意外数据引发错误的解析方法,因此我从您正在使用的拆分/替换方法切换到正则表达式。正则表达式还强制它确实是[object Type]格式也是如此,这似乎是可取的。

然后,为了防止比较的奇怪问题localStorage === window并收到错误,您可以添加类型检查(鸭子类型),非窗口类对象不会通过,这将过滤掉localStorage问题以及具有相同问题的任何其他对象。在这种特殊情况下,我确保对象的类型是"object"并且它有一个名为setInterval。我们可以选择任何众所周知的、得到良好支持的财产window不太可能位于任何其他物体上的物体。在这种情况下,我使用setInterval因为这与 jQuery 在想要知道一个对象是否是窗口时使用的测试相同。请注意,我还更改了代码以不显式比较window完全因为可能有多个window对象(框架、iframe、弹出窗口等),这样,它将为任何窗口对象返回“Window”。

这是代码:

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 );
};

请在此处查看包含各种测试用例的演示:http://jsfiddle.net/jfriend00/euBWV http://jsfiddle.net/jfriend00/euBWV

的期望值"[object Storage]"您为了解析出“Storage”类名而进行的操作来自内部[[Class]]中定义的属性ECMAScript 规范 http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf。在第 8.6.2 节中,规范定义了特定的类名称"Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String"。它没有为主机对象定义类名,例如localStorage因此,这要么留给各个浏览器,要么在其他一些规范文档中找到。

此外,规范还提到了这一点[[Class]]:

[[Class]] 内部属性的值在内部使用 区分不同种类的物体。注意这个规范 不为程序提供任何访问该值的方法,除了 通过 Object.prototype.toString (参见 15.2.4.2)。

并且,我们在 15.2.4.2 中找到了生成输出的规范,例如[object Array] or [object String]通过使用[[Class]作为第二个词。

So, Object.prototype.toString这就是它应该如何工作的。显然IE8在这方面存在buglocalStorage目的。我们无法知道 IE8 内部是否toString()没有使用[[Class]]或者是否[[Class]]未正确设置。无论如何,看来console.log()在IE8中不直接使用Object.prototype.toString()因为它会产生不同的结果。

的行为"" + obj解决方法更难理解。该规范描述了对象到字符串的类型强制应该如何工作。遵循整个规范的线索有点复杂,因为一个部分依赖于另一个部分,而另一个部分又依赖于另一个部分,依此类推。但是,最终,它执行内部方法ToString(ToPrimitive(input argument, hint String))显然在 IE8 中,ToPrimitive当传递一个我们想要一个字符串的提示时,它给了我们实际的类名Object.prototype.toString()不是。规范中有一条蜿蜒穿过的路径[[DefaultValue]]这可能就是 IE8 中发生这种情况的方式,但由于我们已经知道 IE8 没有遵循规范的第一部分,而且它通常也不擅长遵循规范,因此假设它遵循规范并不是一个有效的假设在这方面。最后,我们只知道 IE8 中对 string 的类型强制最终给了我们[[Class]]我们想要的。

作为一个有趣的测试,我在 Chrome 浏览器中尝试了我的测试套件,运行所有作为对象的测试用例"" + obj解决方法(通常代码仅在以下情况下使用该路径)Object.prototype.toString()不返回除以下名称之外的名称"Object"。它适用于除数组之外的所有内容。我认为这意味着[[DefaultValue]]对于物体来说一般是[[Class]](除非对象类型决定它有一个更好的默认值Array显然是这样)。因此,我认为我们已经确认修复 IE8 的解决方法实际上应该按照规范工作。因此,它不仅是 IE8 的解决方法,而且是访问[[Class]]name 如果对象类型没有实现不同的默认值。

所以,我提出的这个新代码实际上是通过规范执行的伪代码:

  1. 尝试获取内部变量[[Class]] using Object.prototype.toString()
  2. 如果这给我们带来了除了"Object"然后,使用它
  3. 否则,使用"" + obj尝试获取字符串版本[[DefaultValue]]
  4. 如果返回有用的东西,请使用它
  5. 如果我们仍然没有比这更有用的东西"Object",然后返回"Object"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

奇怪的 IE8 内部 [[ class ]] 属性行为 的相关文章

随机推荐

  • DestinationViewController Segue 和 UINavigationController swift

    所以我有一个像这样的prepareForSegue方法 override func prepareForSegue segue UIStoryboardSegue sender AnyObject if segue identifier f
  • 使用 TripleDes、PKCS7 和 ECB 进行 PHP 加密/解密

    我的加密函数工作正常 但是我不知道如何让解密函数给出正确的输出 这是我的加密函数 function Encrypt data secret Generate a key from a hash key md5 utf8 encode sec
  • Zipalign - 未找到命令 - MAC 终端

    当我尝试在 apk 上运行 Zipalign 时 出现错误 Command not found 我不太熟悉在 MAC 上使用终端命令 但我已导航到 SDK Tools 文件夹并运行以下命令 zipalign v 4 Project1 apk
  • 将 Swift 与 Qt 结合使用

    我们可以很容易地使用Qt 中的 Objective C 和 C https stackoverflow com questions 23404158 qt run object c code 23404257 23404257 观看了 Ap
  • jQuery:动画后 div 弹回完整尺寸

    在下面的 jQuery 示例中 我将一个 div 放在另一个 div 中 当我将内部 div 的宽度设置为 0 时 外部 div 具有绝对定位 的宽度也会随之减小 这是所希望的 问题是 动画完成后 外部 div 会弹回到原来的大小 这是预期
  • Adobe AIR - 带图像的自定义预加载器

    Folks 我设计了一个Adobe AIR应用 我想展示一些preloader在它打开之前 任何人都可以指导我的教程preloader 专门针对 AIR或者任何已经内置的 Thanks 借助 AIR 我可以想出几种方法来实现这一目标 1 使
  • 无法解决此引用错误

    我一直在编写一个程序 在程序中我必须压缩一些文件 所以我使用了一个名为 Ionic Zip 的插件 当我运行我的程序时 它完全正常 没有错误 但是现在当我在完成编写后尝试构建我的程序时 出现以下错误 Code Warning 1 Could
  • Wcf服务继承(扩展服务)

    我正在开发的程序使用 wcf 公开回调和服务 基本上 服务所做的只是返回一些变量值 至于回调 他们只是更新这些变量 我希望能够公开一个仅包含服务的类以及一个包含服务和回调的类 例如 ServiceContract ServiceBehavi
  • 在带有环回后端的 Angular 应用程序中通过 facebook 登录

    我正在使用 Strongloop 环回后端制作一个有角度的应用程序 我还使用环回护照模块通过 facebook 集成了第三方登录 Loopback example passport 中的一切都很好 并且在重定向到我的应用程序之前 我的应用程
  • 如何获取 PowerShell 脚本的文件系统位置?

    我有一个 PowerShell 脚本位于D temp 当我运行此脚本时 我希望列出文件的当前位置 我该怎么做呢 例如 此代码将在 DOS 批处理文件中完成它 我正在尝试将其转换为 PowerShell 脚本 FOR f usebackq t
  • 匹配 SHA1 的正则表达式

    我正在尝试将通用文本中的 SHA1 与正则表达式进行匹配 理想情况下 我想避免匹配单词 可以肯定地说 完整的 SHA1 具有独特的模式 它们很长且长度一致 因此我可以可靠地匹配它们 但缩写的 SHA1 又如何呢 我可以依赖数字的存在吗 查看
  • 发出蜂鸣声直到有任何输入

    我正在制作一个测验程序 所以我想要的是 每当用户提出任何问题时 他都有 30 秒的时间来回答 在这 30 秒内 我希望每隔 1 秒发出一次嘟嘟声 a 现在我想要的是 一旦用户输入任何输入 这种蜂鸣声就应该停止 我创建了这个小函数来产生 30
  • 玩:如何从 JSON 中删除没有值的字段并用它们创建一个新的 JSON

    给定以下 JSON field1 value1 field2 field3 value3 field4 如何获取两个不同的 JSON 一个包含有值的字段 另一个包含没有值的字段 最终结果应如下所示 field1 value1 field3
  • 一组值的所有可能分组的数量?

    我想找到一个组合公式 给定一定数量的整数 我可以找到这些整数的所有可能分组的数量 这样所有值都属于一个组 假设我有 3 个整数 1 2 3 将有 5 组 1 2 3 1 2 3 1 2 3 1 2 3 2 1 3 我已经通过计算计算了 N
  • 启动 hadoop 流作业的替代方法

    我可以从终端成功启动 hadoop 流作业 但我正在寻找通过 api eclipse 或其他方式启动流作业的方法 我发现的最接近的是这篇文章https stackoverflow com questions 11564463 remotel
  • 如何优化分配恒定股息?

    优化为除以众所周知 gcc 对常量进行了很好的优化 现在我想知道如何dividing常数被优化 gcc 不能帮助我 clang 也是如此 也许我不擅长搜索这些信息 但我找不到关于优化的材料除常数 相比之下 除以常数介绍得很好 include
  • 无法在 NetBeans 中创建 Java Web 应用程序

    我想使用 NetBeans 7 0 1 编写一个 java Web 应用程序 但我找不到该选项Java Web in File gt New Project 我需要获得任何特殊的 Java 版本才能做到这一点吗 转到 工具 菜单并选择 插件
  • 有没有办法扩展 ThreeJS 对象?

    我正在使用 ThreeJS 创建一个交互 人们可以在其中单击立方体 然而 这些立方体在单击时的行为有所不同 不同的颜色动画 以保持想法简单 我的想法是创建 THREE Mesh 对象的扩展类并添加我的自定义函数和属性 这将有助于隔离多维数据
  • 更改 UINavigationBar 外观背景时状态栏颜色发生变化

    我使用这行代码来更改导航栏背景 UINavigationBar appearance setBackgroundImage UIImage imageNamed image png forBarMetrics UIBarMetricsDef
  • 奇怪的 IE8 内部 [[ class ]] 属性行为

    我最近在使用 IE8 目前我不知道 9 时遇到了一些麻烦 无法读取和比较某些值 Class 特性 事实上 这仅适用于以下情况localStorage object 我正在使用这样的方法 var ToStr Object prototype