[javascript] 변수가 배열인지 감지하는 방법

JavaScript의 변수가 배열인지 여부를 결정하는 데 가장 좋은 사실상의 표준 크로스 브라우저 방법은 무엇입니까?

웹 검색에는 여러 가지 제안이 있으며, 일부는 훌륭하고 일부는 유효하지 않습니다.

예를 들어 다음은 기본적인 접근 방식입니다.

function isArray(obj) {
    return (obj && obj.length);
}

그러나 배열이 비어 있거나 obj가 실제로 배열이 아니지만 길이 속성 등을 구현하면 어떤 일이 발생하는지 확인하십시오.

그렇다면 실제로 작동하고 브라우저를 넘나들며 효율적으로 수행하는 측면에서 가장 좋은 구현은 무엇입니까?



답변

JS에서 객체의 유형 검사는를 통해 수행됩니다 instanceof.

obj instanceof Array

각 프레임에 자체 Array개체 가 있기 때문에 개체가 프레임 경계를 넘어 전달되는 경우에는 작동하지 않습니다 . 개체 의 내부 [[Class]] 속성을 확인하여이 문제를 해결할 수 있습니다 . 그것을 얻으려면 다음을 사용하십시오 Object.prototype.toString()(ECMA-262에서 작동하는 것이 보장됩니다) :

Object.prototype.toString.call(obj) === '[object Array]'

두 방법 모두 실제 배열에 대해서만 작동하며 arguments객체 또는 노드 목록 과 같은 배열과 유사한 객체가 아닙니다 . 모든 배열과 같은 객체에는 숫자 length속성 이 있어야 하므로 다음과 같이 확인합니다.

typeof obj !== 'undefined' && obj !== null && typeof obj.length === 'number'

문자열은이 검사를 통과하므로 IE가 인덱스로 문자열의 문자에 액세스하는 것을 허용하지 않기 때문에 문제가 발생할 수 있습니다. 따라서, 당신은 변경할 수 있습니다 typeof obj !== 'undefined'하는 typeof obj === 'object'구별 유형 프리미티브 및 호스트 개체를 제외 할 'object'alltogether을. 이것은 여전히 ​​문자열 객체를 통과시킬 수 있으며, 수동으로 제외해야합니다.

대부분의 경우 실제로 알고 싶은 것은 숫자 인덱스를 통해 객체를 반복 할 수 있는지 여부입니다. 따라서 객체에 0대신 이름이 지정된 속성이 있는지 확인하는 것이 좋습니다 . 다음 검사 중 하나를 통해 수행 할 수 있습니다.

typeof obj[0] !== 'undefined' // false negative for `obj[0] = undefined`
obj.hasOwnProperty('0') // exclude array-likes with inherited entries
'0' in Object(obj) // include array-likes with inherited entries

객체로의 캐스트는 배열과 같은 기본 요소 (예 : 문자열)에 대해 올바르게 작동하는 데 필요합니다.

다음은 JS 배열에 대한 강력한 검사를위한 코드입니다.

function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}

그리고 반복 가능한 (비어 있지 않은) 배열과 같은 객체 :

function isNonEmptyArrayLike(obj) {
    try { // don't bother with `typeof` - just access `length` and `catch`
        return obj.length > 0 && '0' in Object(obj);
    }
    catch(e) {
        return false;
    }
}


답변

ECMAScript 5th Edition이 출시되면서 변수가 배열 인 경우 가장 확실한 테스트 방법 인 Array.isArray ()가 제공됩니다 .

Array.isArray([]); // true

여기에 허용 대답은 대부분의 브라우저에 대한 프레임과 창문을 통해 작동하지만, 그것은 낮은 인터넷 익스플로러 7이 켜지지 않고 있기 때문에, Object.prototype.toString반환하는 다른 창에서라는 배열에 [object Object]하지 [object Array]. IE 9도이 동작으로 회귀 한 것으로 보입니다 (아래 업데이트 된 수정 사항 참조).

모든 브라우저에서 작동하는 솔루션을 원한다면 다음을 사용할 수 있습니다.

(function () {
    var toString = Object.prototype.toString,
        strArray = Array.toString(),
        jscript  = /*@cc_on @_jscript_version @*/ +0;

    // jscript will be 0 for browsers other than IE
    if (!jscript) {
        Array.isArray = Array.isArray || function (obj) {
            return toString.call(obj) == "[object Array]";
        }
    }
    else {
        Array.isArray = function (obj) {
            return "constructor" in obj && String(obj.constructor) == strArray;
        }
    }
})();

완전히 깨지지는 않지만 누군가가 깨뜨 리려고 애쓰는 사람에 의해서만 깨질 것입니다. IE7 이하 및 IE9의 문제를 해결합니다. 이 버그는 IE 10 PP2에 여전히 존재 하지만 출시 전에 수정 될 수 있습니다.

추신, 솔루션에 대해 확실하지 않은 경우 마음에 드는 내용을 테스트하거나 블로그 게시물을 읽는 것이 좋습니다. 조건부 컴파일을 사용하는 것이 불편하다면 다른 잠재적 인 해결책이 있습니다.


답변

Crockford는 “The Good Parts”의 106 페이지에 두 가지 답변이 있습니다. 첫 번째는 생성자를 확인하지만 다른 프레임이나 창에서 거짓 부정을 제공합니다. 두 번째는 다음과 같습니다.

if (my_value && typeof my_value === 'object' &&
        typeof my_value.length === 'number' &&
        !(my_value.propertyIsEnumerable('length')) {
    // my_value is truly an array!
}

Crockford는이 버전이 arguments어레이 메소드가 없더라도 어레이를 어레이로 식별 할 것이라고 지적 합니다.

문제에 대한 그의 흥미로운 논의는 105 페이지에서 시작됩니다.

여기 에이 제안을 포함하는 흥미로운 논의가 있습니다 .

var isArray = function (o) {
    return (o instanceof Array) ||
        (Object.prototype.toString.apply(o) === '[object Array]');
};

모든 토론으로 인해 무언가가 배열인지 아닌지 결코 알고 싶지 않습니다.


답변

jQuery는 isArray 함수를 구현하는데,이를 수행하는 가장 좋은 방법은 다음과 같습니다.

function isArray( obj ) {
    return toString.call(obj) === "[object Array]";
}

(jQuery v1.3.2에서 가져온 스 니펫-문맥에 맞도록 약간 조정 됨)


답변

전문가 John Resig 및 jquery에서 훔치기 :

function isArray(array) {
    if ( toString.call(array) === "[object Array]") {
        return true;
    } else if ( typeof array.length === "number" ) {
        return true;
    }
    return false;
}


답변

배열이라고 결정하면 값으로 무엇을 하시겠습니까?

예를 들어 포함 된 값 이 배열처럼 보이 거나 해시 테이블로 사용되는 객체 인 경우 포함 된 값을 열거하려는 경우 다음 코드가 원하는 것을 가져옵니다 (이 코드는 클로저 함수가 다른 것을 반환 할 때 중지됩니다). “정의되지 않음”보다. COM 컨테이너 또는 열거 형을 반복하지 않습니다. 이는 독자를위한 연습으로 남겨집니다.)

function iteratei( o, closure )
{
    if( o != null && o.hasOwnProperty )
    {
        for( var ix in seq )
        {
            var ret = closure.call( this, ix, o[ix] );
            if( undefined !== ret )
                return ret;
        }
    }
    return undefined;
}

(참고 : “o! = null”은 null 및 undefined 모두에 대해 테스트)

사용 예 :

// Find first element who's value equals "what" in an array
var b = iteratei( ["who", "what", "when" "where"],
    function( ix, v )
    {
        return v == "what" ? true : undefined;
    });

// Iterate over only this objects' properties, not the prototypes'
function iterateiOwnProperties( o, closure )
{
    return iteratei( o, function(ix,v)
    {
        if( o.hasOwnProperty(ix) )
        {
            return closure.call( this, ix, o[ix] );
        }
    })
}


답변

CouchDB (SpiderMonkey)에서이 작업을 수행하는 경우

Array.isArray(array)

array.constructor === Array또는 array instanceof Array작동하지 않습니다. 사용 array.toString() === "[object Array]"은 작동하지만 비교하면 꽤 어리석은 것처럼 보입니다.