Як виправити масив indexOf () у JavaScript для браузерів Internet Explorer


295

Якщо ви працювали з JavaScript будь-якої тривалості, вам відомо, що Internet Explorer не реалізує функцію ECMAScript для Array.prototype.indexOf () [включаючи Internet Explorer 8]. Це не величезна проблема, адже ви можете розширити функціональність на своїй сторінці за допомогою наступного коду.

Array.prototype.indexOf = function(obj, start) {
     for (var i = (start || 0), j = this.length; i < j; i++) {
         if (this[i] === obj) { return i; }
     }
     return -1;
}

Коли я повинен це здійснити?

Чи слід обробляти його на всіх своїх сторінках за допомогою наступної перевірки, яка перевіряє, чи існує функція прототипу, а якщо ні, продовжувати та розширювати прототип масиву?

if (!Array.prototype.indexOf) {

    // Implement function here

}

Або перевірити браузер, і якщо це Internet Explorer, тоді просто застосуйте його?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}

Насправді Array.prototype.indexOfне є частиною ECMA-262 / ECMAScript. Дивіться ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Можливо, ви думаєте String.prototype.indexOf...
Crescent Fresh

5
Це розширення, а не частина оригінального стандарту. Однак він повинен бути реалізований як частина Javascript 1.6 (чого IE не вдається зробити) developer.mozilla.org/uk/New_in_JavaScript_1.6
Джош Стодола

1
@Josh: якраз посилався на "IE не реалізує функцію ECMAScript ..."
Crescent Fresh

4
Ваша реалізація Array.indexOfне враховує негативні стартові індекси. Дивіться пропозицію Mozilla щодо зупинки розриву тут: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf

3
Я оновив питання, щоб використовувати "===", тому що я переживаю, що люди скопіюють його з "==", і це було б неправильно - крім того, що це добре. Дивіться відповідь Елі Грей.
joshcomley

Відповіді:


213

Робіть це так ...

if (!Array.prototype.indexOf) {

}

Як рекомендована сумісність MDC .

Взагалі код виявлення браузера - це велика ні-ні.


У мене не вистачає представника, щоб редагувати питання, але сміливо видаляйте лінгво ECMAScript і замінюйте відповідним формулюванням. Ще раз дякую
Боббі Боршич

12
Будьте обережні, якщо ви використовуєте такий спосіб виявлення. Інша бібліотека може реалізувати цю функцію перед її тестуванням, і вона може не відповідати стандартам (прототип це зробив деякий час тому). Якби я працював у неприязному середовищі (безліч інших кодерів, що використовують безліч різних бібліотек), я б нікому з них не довіряв ...
Пабло Кабрера

Стовпчик "Зв'язане" ---> справді зручно! Я люблю відповідь тут: stackoverflow.com/questions/1744310/…
gordon

Чи потрібно його обгортати у кожному js-файлі?
rd22

Хто саме MDC?
Феррібіг

141

Крім того, ви можете використовувати функцію jQuery 1.2 inArray , яка повинна працювати в браузерах:

jQuery.inArray( value, array [, fromIndex ] )

'IndexOf' є нативним кодом (праворуч), тому jQuery 'inArray ()' буде таким же швидким, як використання нативної, коли вона доступна, і полі-заповнення, коли ні?
Jeach

10
Гаразд, щоб відповісти на мій власний коментар (вище), я щойно реалізував його, і в Chrome це так само швидко, як і коли я використовував 'indexOf ()', але в IE 8 це дуже, дуже повільно ... так що, принаймні, ми знаємо що 'inArray ()' використовує нативні можливості, коли це можливо.
Jeach

78

Повний код тоді буде таким:

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(obj, start) {
         for (var i = (start || 0), j = this.length; i < j; i++) {
             if (this[i] === obj) { return i; }
         }
         return -1;
    }
}

Щоб отримати ретельну відповідь та код на це, а також інші функції масиву, перегляньте питання щодо переповнення стека. Виправлення функцій масиву JavaScript у Internet Explorer (indexOf, forEach тощо) .


2
дякую за те, що ви просто отримали повну справу. Я часто відвідую цю сторінку, коли мені потрібен кросплатформенний indexOf у новому проекті, і ваш фрагмент є єдиним із повним кодом. :) Ці кілька секунд дійсно складаються, коли один відвідує цю сторінку.
dylnmc

16

Бібліотека underscore.js має функцію indexOf, яку ви можете використовувати замість цього:

_.indexOf([1, 2, 3], 2)

4
Ця відповідь дозволяє уникнути возитися з прототипом масиву , і він делегує до нативного indexOf, коли він є. Мені це подобається.
Бред Кох

Здається, це найпростіший спосіб, якщо ви зможете включити підкреслення або подачу
ChrisRich

10

Ви повинні перевірити, чи не визначено це за допомогою if (!Array.prototype.indexOf).

Крім того, ваша реалізація indexOfне є коректною. Ви повинні використовувати ===замість цього ==у своїй if (this[i] == obj)заяві, інакше [4,"5"].indexOf(5)це буде 1 відповідно до вашої реалізації, що невірно.

Я рекомендую вам скористатися реалізацією на MDC .


9

Є офіційне рішення Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

(function() {
    /**Array*/
    // Production steps of ECMA-262, Edition 5, 15.4.4.14
    // Reference: http://es5.github.io/#x15.4.4.14
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(searchElement, fromIndex) {
            var k;
            // 1. Let O be the result of calling ToObject passing
            //    the this value as the argument.
            if (null === this || undefined === this) {
                throw new TypeError('"this" is null or not defined');
            }
            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 len is 0, return -1.
            if (len === 0) {
                return -1;
            }
            // 5. If argument fromIndex was passed let n be
            //    ToInteger(fromIndex); else let n be 0.
            var n = +fromIndex || 0;
            if (Math.abs(n) === Infinity) {
                n = 0;
            }
            // 6. If n >= len, return -1.
            if (n >= len) {
                return -1;
            }
            // 7. If n >= 0, then Let k be n.
            // 8. Else, n<0, Let k be len - abs(n).
            //    If k is less than 0, then let k be 0.
            k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
            // 9. Repeat, while k < len
            while (k < len) {
                // 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
                //    i.  Let elementK be the result of calling the Get
                //        internal method of O with the argument ToString(k).
                //   ii.  Let same be the result of applying the
                //        Strict Equality Comparison Algorithm to
                //        searchElement and elementK.
                //  iii.  If same is true, return k.
                if (k in O && O[k] === searchElement) {
                    return k;
                }
                k++;
            }
            return -1;
        };
    }
})();

1
Бути педантичним, але MDN - це не лише Mozilla. Це проект, керований громадою, який містить співробітників Mozilla, але також і волонтерів, кожен може приєднатися та зробити свій внесок.
ste2425

5

Я б рекомендував це всім, хто шукає функцію, яка відсутня:

http://code.google.com/p/ddr-ecma5/

Він надає більшість відсутніх функцій ecma5 для старших броуерів :)


** Хоча я зазначу, що у мене були проблеми в IE7 з цією lib.
Джош Мак

2

Це було моєю реалізацією. По суті, додайте це перед будь-якими іншими сценаріями на сторінці. тобто у вашого майстра щодо глобального рішення для Internet Explorer 8. Я також додав у функцію обрізки, яка, здається, використовується у багатьох рамках.

<!--[if lte IE 8]>
<script>
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(obj, start) {
            for (var i = (start || 0), j = this.length; i < j; i++) {
                if (this[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
    }

    if(typeof String.prototype.trim !== 'function') {
        String.prototype.trim = function() {
            return this.replace(/^\s+|\s+$/g, '');
        };
    };
</script>
<![endif]-->

2

це працює для мене.

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(elt /*, from*/) {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)? Math.ceil(from) : Math.floor(from);
    if (from < 0)
    from += len;

    for (; from < len; from++) {
      if (from in this && this[from] === elt)
        return from;
    }
    return -1;
  };
}

1

За допомогою Underscore.js

var arr=['a','a1','b'] _.filter(arr, function(a){ return a.indexOf('a') > -1; })

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.