因为一些原因(例如一些旧项目需要ActiveX控件等),需要支持旧版本IE浏览器,但是现在很多框架可能已经不支持IE浏览器,比如里面使用了一些IE不兼容的Array的方法,例如find,filter,map,findIndex,includes
IE下可能会报如下错误:
以下代码,我把能想到的IE下可能不支持的方法列出来,并实现了,大家各取所需:
if(!Array.prototype.find) { Array.prototype.find = function (callback) { return callback && (this.filter(callback) || [])[0]; }; } if (!Array.prototype.findIndex) { Object.defineProperty(Array.prototype, 'findIndex', { value: function(predicate) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception. if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. var thisArg = arguments[1]; // 5. Let k be 0. var k = 0; // 6. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kValue be ? Get(O, Pk). // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). // d. If testResult is true, return k. var kValue = o[k]; if (predicate.call(thisArg, kValue, k, o)) { return k; } // e. Increase k by 1. k++; } // 7. Return -1. return -1; } }); } if (!Array.prototype.includes) { Object.defineProperty(Array.prototype, 'includes', { value: function(valueToFind, fromIndex) { if (this == null) { throw new TypeError('"this" is null or not defined'); } // 1. Let O be ? ToObject(this value). var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If len is 0, return false. if (len === 0) { return false; } // 4. Let n be ? ToInteger(fromIndex). // (If fromIndex is undefined, this step produces the value 0.) var n = fromIndex | 0; // 5. If n ≥ 0, then // a. Let k be n. // 6. Else n < 0, // a. Let k be len + n. // b. If k < 0, let k be 0. var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); function sameValueZero(x, y) { return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); } // 7. Repeat, while k < len while (k < len) { // a. Let elementK be the result of ? Get(O, ! ToString(k)). // b. If SameValueZero(valueToFind, elementK) is true, return true. if (sameValueZero(o[k], valueToFind)) { return true; } // c. Increase k by 1. k++; } // 8. Return false return false; } }); } // Production steps of ECMA-262, Edition 5, 15.4.4.19 // Reference: http://es5.github.io/#x15.4.4.19 if (!Array.prototype.map) { Array.prototype.map = function(callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(' this is null or not defined'); } // 1. Let O be the result of calling ToObject passing the |this| // value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal // method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 1) { T = thisArg; } // 6. Let A be a new array created as if by the expression new Array(len) // where Array is the standard built-in constructor with that name and // len is the value of len. A = new Array(len); // 7. Let k be 0 k = 0; // 8. Repeat, while k < len while (k < len) { var kValue, mappedValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal // method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal // method of O with argument Pk. kValue = O[k]; // ii. Let mappedValue be the result of calling the Call internal // method of callback with T as the this value and argument // list containing kValue, k, and O. mappedValue = callback.call(T, kValue, k, O); // iii. Call the DefineOwnProperty internal method of A with arguments // Pk, Property Descriptor // { Value: mappedValue, // Writable: true, // Enumerable: true, // Configurable: true }, // and false. // In browsers that support Object.defineProperty, use the following: // Object.defineProperty(A, k, { // value: mappedValue, // writable: true, // enumerable: true, // configurable: true // }); // For best browser support, use the following: A[k] = mappedValue; } // d. Increase k by 1. k++; } // 9. return A return A; }; } if (!Array.prototype.filter){ Array.prototype.filter = function(fun /*, thisArg */){ "use strict"; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") throw new TypeError(); var res = []; var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++){ if (i in t){ var val = t[i]; if (fun.call(thisArg, val, i, t)) res.push(val); } } return res; }; } if (!Array.prototype.some){ Array.prototype.some = function(fun /*, thisArg */) { 'use strict'; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== 'function') throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t && fun.call(thisArg, t[i], i, t)) return true; } return false; }; } if (!Array.prototype.every) { Array.prototype.every = function(fun /*, thisArg */) { 'use strict'; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== 'function') throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t && !fun.call(thisArg, t[i], i, t)) return false; } return true; }; } if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; } if(!Array.indexOf){ Array.prototype.indexOf = function(obj){ for(var i=0; i<this.length; i++){ if(this[i]==obj){ return i; } } return -1; } } // Production steps of ECMA-262, Edition 5, 15.4.4.18 // Reference: http://es5.github.io/#x15.4.4.18 if (!Array.prototype.forEach) { Array.prototype.forEach = function(fun /*, thisp*/){ var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++){ if (i in this) fun.call(thisp, this[i], i, this); } }; }
一些方法的解释
forEach
forEach 是在最近被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调用 forEach 之前 插入下面的代码,在本地不支持的情况下使用 forEach。该算法是 ECMA-262 第5版中指定的算法。算法假定 Object 和 TypeError 拥有它们的初始值。callback.call 等价于 Function.prototype.call
bind
bind 函数在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。你可以部份地在脚本开头加入以下代码,就能使它运作,让不支持的浏览器也能使用 bind() 功能。
filter
filter 被添加到 ECMA-262 标准第 5 版中,因此在某些实现环境中不被支持。可以把下面的代码插入到脚本的开头来解决此问题,该代码允许在那些没有原生支持 filter 的实现环境中使用它。该算法是 ECMA-262 第 5 版中指定的算法,假定 fn.call 等价于 Function.prototype.call 的初始值,且 Array.prototype.push 拥有它的初始值。
some
在第 5 版时,some 被添加进 ECMA-262 标准;这样导致某些实现环境可能不支持它。你可以把下面的代码插入到脚本的开头来解决此问题,从而允许在那些没有原生支持它的实现环境中使用它。该算法是 ECMA-262 第 5 版中指定的算法,假定 Object 和 TypeError 拥有他们的初始值,且 fun.call 等价于 Function.prototype.call。
every
在第 5 版时,every 被添加进 ECMA-262 标准;因此在某些实现环境中不被支持。你可以把下面的代码放到脚本的开头来解决此问题,该代码允许在那些没有原生支持 every 的实现环境中使用它。该算法是 ECMA-262 第5版中指定的算法,假定 Object 和 TypeError 拥有它们的初始值,且 fun.call 等价于 Function.prototype.call。
map
map 是在最近的 ECMA-262 标准中新添加的方法;所以一些旧版本的浏览器可能没有实现该方法。在那些没有原生支持 map 方法的浏览器中,你可以使用下面的 Javascript 代码来实现它。所使用的算法正是 ECMA-262,第 5 版规定的。假定Object, TypeError, 和 Array 有他们的原始值。而且 callback.call 的原始值也是 Function.prototype.call
文章评论