Як виправити масив 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.