for .... in 存在的兼容问题你造吗?

来源:互联网 发布:用友软件怎么安装 编辑:程序博客网 时间:2024/05/16 10:24
在js中for_in主要是用来遍历对象的可枚举属性,包括原型链上的属性。然而for_in在IE < 9下可能会出现问题。for_in要出现问题必须满足两个条件:   1:IE < 9;   2:某些不可枚举的属性被重写。在js中当一些不可枚举的属性比如toString被重写后,它会变成可枚举。然而当你碰上了IE<9,这些被重写的属性依旧
是不可枚举无法使用for_in去遍历。那么如何在IE<9的情况下去搜集这些被重写的不可枚举属性。思路:  一、先重写一个不可枚举属性并用propertyIsEnumerable去检测是否可枚举来判断是否是IE < 9;  二、将不可枚举的属性组成数组以待后续遍历;  三、先拿到对象的原型,constructor属性要单独检测,至于为什么,个人感觉是因为并不是所有对象都有constructor,只有通过构造函数得到的对象才有该属性,检测constructor属性,在排除原型链的情况下判断对象上是否具有constructor属性并且得到的属性数组中
不包含constructor。其他属性,主要是从不可枚举的属性数组中遍历,判断属性数组中是否包含此属性并且该属性属
于该对象并且原型上的该属性不等于该对象上此属性。underscore.js中给出以下方法。  一、首先定义hasEnumBug来判断是否是IE<9    var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');//返回false  二、然后列出IE<9下不能用for in来枚举的key值集合    var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];  三、最后搜集方法    var collectNonEnumProps = function(obj, keys) {        var nonEnumIdx = nonEnumerableProps.length;        var constructor = obj.constructor;        //获得原型,两种情况,构造函数和字面量形式 obj.constructor.prototype 和 obj.__proto__        var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;        // `constructor` 属性需要特殊处理        var prop = 'constructor';        //对象重写了constructor 并且keys数组不包含constructor        if (_.has(obj, prop) && !_.contains(keys, prop)) {            keys.push(prop);        }        //遍历nonEnumerableProps数组        while (nonEnumIdx--) {            prop = nonEnumerableProps[nonEnumIdx];            //判断是否重写了不可枚举属性            //in用来判断一个属性是不是属于一个对象,这个属性可以是原型链上的,也可以是不可枚举属性            if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {                keys.push(prop);            }        }    };