怪异的IE8内部[[类]属性的行为 [英] Weird IE8 internal [[ class ]] attribute behavior

查看:131
本文介绍了怪异的IE8内部[[类]属性的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到了一些麻烦与IE8(我不知道在这一点上约9)阅读和比较了一些 [等级] 属性的值。其实这只是在为的localStorage 对象的情况。

I recently had some trouble with IE8 (I don't know about 9 at this point) with reading and comparing the value of some [[Class]] properties. Actually it's only in the case for the 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 );
};

此方法将返回该值,例如:

This method will return this values for instance:

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

这是当然的作品,在所有浏览器,我意识到通过简单的检查从对象自身[类别] 属性。现在,我打电话的localStorage 对象这个方法

That works of course, in all browsers I'm aware of by simply checking that [[Class]] property from an object itself. Now, I'm calling this method on the localStorage object

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

IE8刚刚返回对象在这里。然而,这并不是实际工作问题,当您尝试将的localStorage 对象的窗口对象进行比较的问题发生。正如你所看到的,我检查,如果在参数传递是当前窗口对象

IE8 just returns Object here. However, that is not the actuall problem, the problem happens when you try to compare the localStorage object with the window object. As you can see, I'm checking if the passed in argument is the current window object

if( obj === window ) { }

如果 OBJ 现在是 window.localStorage 的对象,这将是在一个错误结束

If obj now is the window.localStorage object, this will end up in an error

"Class does not support automation"

如果您尝试比较的localStorage 窗口这只是发生,你可以对任何东西,没有任何比较一下麻烦。这只是一个bug或者我可以以某种方式解决这个问题?

This only happens if you try to compare localStorage with window, you can compare it against anything else without any trouble. Is this just another bug or can I workaround this issue somehow ?

我想基本上我的问题是:

I guess basically my question is:

你是怎么知道的IE8(可能是太IE9)如果你正在处理的的localStorage 对象?

How do you know in IE8 (possibly IE9 too) if you're dealing with the localStorage object?

我想要做的最后一件事是内包装与整个方法的的try-catch ,因为它被调用相当频繁。

The last thing I want to do is to inner-wrap the whole method with a try-catch because it gets called fairly often.

要完全混淆我在这里说到:当你做一个的console.log(OBJ)在IE8的控制台就返回 [对象存储] (太好了!),但是如果你调用 Object.prototype.toString.call(OBJ)返回 [对象的对象] 。同样适用于的typeof OBJ ,将返回对象

To entirely confuse me here it comes: When you do a console.log( obj ) in IE8's console it returns you [object Storage] (nice!) but if you call Object.prototype.toString.call( obj ) it returns [object Object]. Same goes for typeof obj, will return object.

第二个问题:

如何IE8的控制台打印出正确的 [等级]

How does the IE8 console print out the correct [[Class]] ?

推荐答案

我已经找到一种方法使用一个隐含的的toString()操作来解决IE8的行为和ECMAScript的规范解释了为什么解决方法是有道理的。隐含的的toString()是这样的:

I've found a way to work around the IE8 behavior using an implicit toString() operation and the ECMAScript spec explains why the work-around makes sense. The implicit toString() is this:

"" + window.localStorage

这是隐式强制为对象的内部调用toString()方法,在IE浏览器,这将返回你想要的理想的形式 [对象存储] ,你可以得到你的code无需特殊外壳上班 window.localStorage

This is implicitly forcing a call to the object's internal toString() method and, in IE, this will return the desired form you want [object Storage] and you can get your code to work without special casing window.localStorage.

所以,我一直在寻找风险最小的方式将其纳入现有的code这一点。选择的方法是得到同样的方式你用得到它的类型和当且仅当它返回一个通用的对象类型,然后查看是否有可用的新方法一个更好的名字。所以,这用来工作就好了所有的事情将继续工作,他们做的方式,我们可能会为一些对象找到一个更好的名字(如 window.localStorage ),它用于返回一个通用的对象的名字。在另一个变化是,我觉得对收益的确切类型,我们可能会从得到更少的信心+ OBJ 结构,所以我想这不会抛出一个分析方法出乎人们意料的数据有误,所以我切换到一个正则表达式从拆分/替换你正在使用的方法。正则表达式也执行,这真的是 [对象类型] 格式而言这似乎是可取的。

So, I was looking for the minimal risk way to incorporate this into your existing code. The approach chosen was to get the type that same way you use to get it and if and only if it returns a generic "Object" type, then see if there is a better name available with the new method. So, all things that used to work just fine will continue to work the way they did and we might find a better name for some objects (like window.localStorage) that used to return a generic "Object" name. The one other change is that I felt less confident about the exact type of return we might get from the "" + obj construct so I wanted a parsing method that wouldn't throw an error on unexpected data so I switched to a regex from the split/replace method you were using. The regex also enforces that it's really the [object Type] format too which seems desirable.

然后,为了防止比较奇怪的问题 localStorage的===窗口并得到一个错误,你可以添加一个类型检查(鸭打字),一个非像对象窗口不会通过,这将筛选出 localStorage的问题和同样的问题的任何其他对象。在这种特殊情况下,我确定物体的类型是对象,它有一个命名属性的setInterval 。我们可以选择任何公知的,在窗口对象,它是不可能是任何其它的物体上的很好的支持属性。在这种情况下,我使用的setInterval ,因为这是同一个测试jQuery的,当它想知道如果对象是一个窗口使用。请注意,我也改变了code规定不明确的比较窗口,因为在所有可以有多个窗口对象(框架,内部框架,弹出窗口,等...),所以这样一来,将返回窗口的窗口对象。

Then, to protect against the odd issue of comparing localStorage === window and getting an error, you can add a type check (duck typing) that a non-window like object would not pass and this will filter out the localStorage issue and any other objects with the same issue. In this particular case, I make sure the type of the object is "object" and that it has a property named setInterval. We could have selected any well known, well supported property of the window object that is unlikely to be on any other object. In this case, I use setInterval because that's the same test that jQuery uses when it wants to know if an object is a window. Note, I also changed the code to not explicitly compare to window at all because there can be more than one window object (frames, iframes, popups, etc...) so this way, it will return "Window" for any window object.

这里的code:

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

See a demo with various test cases here: http://jsfiddle.net/jfriend00/euBWV

的期望值[对象存储],你是以后以解析出存储类的名字来自于内部 [等级] ECMAScript的SPEC 的。在第8.6.2,该规范定义了参数,阵,布尔,日期,错误,功能,JSON,数学具体的类名,编号,对象,正则表达式和字符串。所以要么是留给个人的浏览器或其他一些规范文件被发现,它并不像的localStorage 主机对象定义类的名称。

The desired value of "[object Storage]" that you were after in order to parse out the "Storage" class name comes from the internal [[Class]] property as defined in the ECMAScript spec. In section 8.6.2, the spec defines specific Class names for "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String". It does not define Class names for host objects like localStorage so that is either left to individual browsers or is found in some other spec document.

此外,规范说这个约 [等级]

的值[[类别]]内部属性用于内部
  区分不同类型的对象。注意,本说明书中
  一个程序不提供任何手段来访问不同的是值
  通过Object.prototype.toString(见15.2.4.2)。

The value of a [[Class]] internal property is used internally to distinguish different kinds of objects. Note that this specification does not provide any means for a program to access that value except through Object.prototype.toString (see 15.2.4.2).

和,这是15.2.4.2,我们发现了规范产生像 [对象数组] [对象字符串] <输出/ code>使用 [等级] 作为第二个字。

And, it is in 15.2.4.2 that we find the specification for generating the output like [object Array] or [object String] by using the [[Class] as the second word.

因此​​, Object.prototype.toString 是它是如何工作的。显然,IE8在这方面为的localStorage 对象错误。我们无法知道IE8里面是否的toString()不使用 [等级] 还是 [等级] 设置不正确。在任何情况下,似乎的console.log()在IE8是不能直接使用 Object.prototype.toString(),因为它会产生不同的结果。

So, Object.prototype.toString is how it is supposed to work. Obviously IE8 has bugs in this regard for the localStorage object. We can't know inside of IE8 whether toString() is not using [[Class]] or whether [[Class]] is not set properly. In any case, it appears that console.log() in IE8 is not directly using Object.prototype.toString() because it generates a different result.

的行为+ OBJ 的解决办法是更复杂的理解。该规范描述对象为字符串的类型转换应该是怎样工作的。这是一个有点复杂跟随螺纹一路经过规范的一个部分取决于另一个依赖于另一个等等。但是,最终,它执行的内部方法的ToString(ToPrimitive(输入参数,提示字符串)),显然在IE8, ToPrimitive 当传递我们想要一个字符串给我们实际的类名 Object.prototype.toString()不是暗示。还有就是通过规范,通过蜿蜒的路径 [默认值] 这怎么可能发生这种情况在IE8,但由于我们已经知道IE8没有按照第一部分规范的,它是不是一般擅长反正以下的规范,它不是一个有效的假设,假定它遵循了这方面的天赋。最后,我们只知道这个类型强制转换为字符串IE8最终给我们的 [等级] 是我们想要的。

The behavior of the "" + obj work-around is more complicated to understand. The spec describes how a type coercion of an object to a string is supposed to work. It's a bit complicated to follow the thread all the way through the spec as one part depends upon another which depends upon another and so on. But, in the end, it executes internal methods ToString(ToPrimitive(input argument, hint String)) and apparently in IE8, ToPrimitive when passed a hint that we want a string is giving us the actual class name that Object.prototype.toString() is not. There is a path through the spec that winds through [[DefaultValue]] which may be how this happens in IE8, but since we already know IE8 didn't follow the first part of the spec and it wasn't generally good at following the spec anyway, it's not a valid assumption to assume that it follows the spec in this regard. In the end, we just know that a type coercion to string in IE8 ends up giving us the [[Class]] that we wanted.

作为一个有趣的测试,我想我的测试套件在Chrome浏览器中运行所有的测试用例,可通过+ OBJ 解决方法(通常为对象code只使用路径时, Object.prototype.toString()不会返回比对象,它适用于一切,除了一个数组。我认为,这意味着 [默认值] 一般 [等级] ] (除非对象类型决定它具有更好的默认值阵列显然不会)。所以,我认为我们必须确认制作作品围绕修复IE8实际上应该按照规范来工作。所以,它不仅是一个变通的IE8,但它是一个备用路径来获得在 [等级] 名称如果对象类型不实现不同的默认值。

As an interesting test, I tried my test suite in the Chrome browser running all the test cases that are objects through the "" + obj work-around (normally the code only uses that path when Object.prototype.toString() doesn't return a name other than "Object". It works for everything except an array. I think this means that the [[DefaultValue]] for objects is generally [[Class]] (unless the object type decides it has a better default value which Array apparently does). So, I think we have confirmation that the work-around that fixes IE8 is actually supposed to work per the spec. So, not only is it a work-around for IE8, but it's an alternate path to get at the [[Class]] name if the object type doesn't implement a different default value.

所以,真的是我提出的这个新的code是通过规​​范做的是这个伪code:

So, really what this new code I've proposed is doing via the spec is this pseudo code:


  1. 尝试获得在内部变量 [等级] 使用 Object.prototype.toString()

  2. 如果这给了我们其他的东西比对象然后,使用它

  3. 否则,使用+ OBJ 来试图获得在字符串版本 [默认值]

  4. 如果返回一些有用的东西,用它

  5. 如果我们还没有比更有用的东西对象,那么就返回对象

  1. Try to get at the internal variable [[Class]] using Object.prototype.toString()
  2. If that gives us something other than "Object" then, use it
  3. Otherwise, use "" + obj to try to get at the string version of [[DefaultValue]]
  4. If that returns something useful, use it
  5. If we still don't have something more useful than "Object", then just return "Object"

这篇关于怪异的IE8内部[[类]属性的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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