कैसे पता लगाने के लिए कि एक चर एक सरणी है


101

जावास्क्रिप्ट में एक चर एक सरणी है या नहीं यह निर्धारित करने के लिए सबसे अच्छा डी-फैक्टो मानक क्रॉस-ब्राउज़र विधि क्या है?

वेब पर सर्च करने पर कई तरह के सुझाव मिलते हैं, कुछ अच्छे और काफी कुछ अमान्य।

उदाहरण के लिए, निम्नलिखित एक मूल दृष्टिकोण है:

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

हालांकि, ध्यान दें कि क्या होता है यदि सरणी खाली है, या obj वास्तव में एक सरणी नहीं है, लेकिन एक लंबी संपत्ति को लागू करता है, आदि।

तो वास्तव में काम करने, क्रॉस-ब्राउज़र होने और अभी भी कुशलता से प्रदर्शन करने के मामले में कौन सा कार्यान्वयन सबसे अच्छा है?


4
क्या यह वापसी एक तार पर सच नहीं होगी?
जेम्स हगार्ड

दिए गए उदाहरण में स्वयं प्रश्न का उत्तर देने का उल्लेख नहीं है, यह केवल एक उदाहरण है कि एक समाधान कैसे प्राप्त किया जा सकता है - जो अक्सर विशेष मामलों में विफल रहता है (जैसे यह एक, इसलिए "हालांकि, ध्यान दें ...")।
stpe

@ नाम: अधिकांश ब्राउज़रों में (IE को बाहर रखा गया), स्ट्रिंग्स ऐर-लाइक हैं (यानी संख्यात्मक सूचक के माध्यम से पहुंच संभव है)
Christoph

1
खिचड़ी भाषा का मानना ​​है कि ऐसा करना बहुत मुश्किल है ...
क्लाउडी

जवाबों:


160

जेएस में वस्तुओं की प्रकार की जाँच के माध्यम से किया जाता है instanceof, यानी

obj instanceof Array

यह काम नहीं करेगा यदि ऑब्जेक्ट को फ्रेम सीमाओं के पार किया जाता है क्योंकि प्रत्येक फ्रेम का अपना Arrayऑब्जेक्ट होता है। आप ऑब्जेक्ट की आंतरिक [[कक्षा]] संपत्ति की जांच करके इसके आसपास काम कर सकते हैं। इसे पाने के लिए, उपयोग करें 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'

ज्यादातर मामलों में, आप वास्तव में जानना चाहते हैं कि क्या आप संख्यात्मक सूचकांकों के माध्यम से वस्तु पर पुनरावृत्ति कर सकते हैं। इसलिए, यह जांचने के लिए एक अच्छा विचार हो सकता है कि क्या वस्तु के 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

ऑब्जेक्ट के लिए कास्ट एरे-जैसे प्राइमेटी (यानी स्ट्रिंग्स) के लिए सही तरीके से काम करने के लिए आवश्यक है।

यहाँ जेएस सरणियों के लिए मजबूत जाँच के लिए कोड है:

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;
    }
}

7
जेएस सरणी चेकिंग में अत्याधुनिक का शानदार सारांश।
नोसरेडना

MS JS 5.6 (IE6?) के रूप में, "Instof" ऑपरेटर को COM ऑब्जेक्ट (ActiveXObject) के खिलाफ चलाने पर बहुत सारी मेमोरी लीक हो जाती है। जेएस 5.7 या जेएस 5.8 की जांच नहीं की है, लेकिन यह अभी भी सच हो सकता है।
जेम्स हगार्ड

1
@ नाम: दिलचस्प - मुझे इस लीक के बारे में पता नहीं था; वैसे भी, वहाँ एक आसान तय है: IE में, केवल देशी जेएस वस्तुओं में एक hasOwnPropertyविधि है, इसलिए बस अपने instanceofसाथ उपसर्ग करें obj.hasOwnProperty && ; भी, यह अभी भी IE7 के साथ एक मुद्दा है? कार्य प्रबंधक के माध्यम से मेरे सरल परीक्षणों से पता चलता है कि ब्राउज़र को कम करने के बाद मेमोरी पुनः प्राप्त हुई ...
क्रिस्टोफ

@Christoph - IE7 के बारे में निश्चित नहीं है, लेकिन IIRC यह JS 5.7 या 5.8 के लिए बगफिक्स की सूची में नहीं था। हम एक सेवा में सर्वर की ओर से अंतर्निहित JS इंजन को होस्ट करते हैं, इसलिए UI कम से कम लागू नहीं होता है।
जेम्स हगार्ड

1
@TravisJ: ECMA-262 5.1, खंड 15.2.4.2 देखें ; आंतरिक वर्ग के नाम कन्वेंशन अपर केस से हैं - खंड Christ.६.२
क्रिस्टोफ़

42

ECMAScript 5 वें संस्करण का आगमन हमें परीक्षण का सबसे निश्चित तरीका बताता है यदि कोई चर एक सरणी, 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 में समस्याओं के आसपास काम करता है। आईई 10 पीपी 2 में अभी भी बग मौजूद है , लेकिन रिलीज से पहले इसे ठीक किया जा सकता है।

पुनश्च, यदि आप समाधान के बारे में अनिश्चित हैं, तो मैं आपको अपने दिल की सामग्री और / या ब्लॉग पोस्ट पढ़ने के लिए इसका परीक्षण करने की सलाह देता हूं। यदि आप सशर्त संकलन का उपयोग करने में असहज हैं, तो अन्य संभावित समाधान हैं।


स्वीकृत उत्तर IE8 + में ठीक काम करता है, लेकिन IE6,7 में नहीं
user123444555621

@ Pumbaa80: आप सही हैं :-) IE8 अपने स्वयं के Object.prototype.toString के लिए समस्या को हल करता है, लेकिन IE8 दस्तावेज़ मोड में बनाई गई सरणी का परीक्षण करना जो IE7 या निम्न दस्तावेज़ मोड में पास किया जाता है, समस्या बनी रहती है। मैंने केवल इस परिदृश्य का परीक्षण किया था और आसपास के अन्य तरीके से नहीं। मैंने इस फिक्स को केवल IE7 और लोअर पर लागू करने के लिए संपादित किया है।
एंडी ई

WAAAAAAA, मुझे IE से नफरत है। मैं पूरी तरह से अलग "दस्तावेज़ मोड", या "सिज़ो मोड" के बारे में भूल गया, जैसा कि मैं उन्हें कॉल करने वाला हूं।
user123444555621

जबकि विचार महान हैं और यह अच्छा लग रहा है, यह मेरे लिए IE9 में पॉपअप विंडो के साथ काम नहीं करता है। यह सलामी बल्लेबाज द्वारा बनाई गई सरणियों के लिए गलत है ... क्या कोई IE9 कॉम्पिटबेल समाधान है? (समस्या यह है कि IE9 को लागू करता है Array.isArray को लगता है, जो दिए गए मामले के लिए गलत है, जब यह नहीं करना चाहिए।
स्टीफन हील

@Steffen: दिलचस्प है, इसलिए मूल isArrayदस्तावेज़ अन्य दस्तावेज़ मोड में बनाए गए सरणियों से सही वापस नहीं आता है? मुझे इस पर ध्यान देना होगा जब मुझे कुछ समय मिलेगा, लेकिन मुझे लगता है कि सबसे अच्छी बात यह है कि कनेक्ट पर एक बग दर्ज करें ताकि इसे IE 10. में तय किया जा सके
एंडी ई

8

क्रॉकफोर्ड के "द गुड पार्ट्स" के पृष्ठ 106 पर दो उत्तर हैं। पहला व्यक्ति कंस्ट्रक्टर की जांच करता है, लेकिन विभिन्न फ़्रेमों या खिड़कियों में गलत नकारात्मक देगा। यहाँ दूसरा है:

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

क्रॉकफोर्ड बताते हैं कि यह संस्करण argumentsसरणी को एक सरणी के रूप में पहचानेगा, भले ही इसके पास कोई भी सरणी विधि न हो।

समस्या की उनकी दिलचस्प चर्चा पृष्ठ 105 पर शुरू होती है।

आगे दिलचस्प चर्चा (पोस्ट-गुड पार्ट्स) है जिसमें यह प्रस्ताव शामिल है:

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

सभी चर्चा मुझे कभी भी जानना नहीं चाहती है कि कुछ एक सरणी है या नहीं।


1
यह IE में स्ट्रिंग ऑब्जेक्ट्स के लिए टूट जाएगा और स्ट्रिंग प्राइमिटिव्स को बाहर कर देगा, जो IE में छोड़कर सरणी-जैसे हैं; यदि आप वास्तविक सरणियाँ चाहते हैं तो [[कक्षा]] की जाँच करना बेहतर है; अगर आपको सरणी पसंद वाली वस्तुएं चाहिए, तो चेक imo भी प्रतिबंधात्मक है
Christoph

@ क्रिस्टोफ़ - मैंने एक संपादन के माध्यम से थोड़ा और जोड़ा। आकर्षक विषय।
Nosredna

2

jQuery एक isArray फ़ंक्शन को लागू करता है, जो यह करने का सबसे अच्छा तरीका बताता है

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

(स्निपेट को jQuery v1.3.2 से लिया गया - संदर्भ से समझ में लाने के लिए थोड़ा समायोजित)


वे IE (# 2968) पर झूठे लौटते हैं। (JQuery स्रोत से)
razzed

1
JQuery के स्रोत में यह टिप्पणी isFunction फ़ंक्शन को संदर्भित करती है, isArray को नहीं
मारियो

4
आपको उपयोग करना चाहिए Object.prototype.toString()- जो कि टूटने की संभावना कम है
क्रिस्टोफ

2

गुरु जॉन रेसिग और jquery से चोरी:

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

2
दूसरा परीक्षण एक स्ट्रिंग के लिए भी सही लौटेगा: टाइपोफ़ "एबीसी" .length === "संख्या" // सच
डैनियल वांडर्सलुइस

2
इसके अलावा, मुझे लगता है कि आपको "नंबर" जैसे हार्डकोड प्रकार के नाम कभी नहीं चाहिए। इसके बजाय इसकी तुलना वास्तविक संख्या से करने का प्रयास करें, जैसे टाइपऑफ (obj) == टाइपोफ (42)
ohnoes

5
@mtod: टाइप नाम हार्डकोड क्यों नहीं होना चाहिए? सब के बाद, वापसी मूल्यों का typeofमानकीकरण किया जाता है?
क्रिस्टोफ

1
@ जॉनो अपने आप को समझाते हैं
पचेरियर

1

एक बार यह तय करने के बाद कि आप मूल्य के साथ क्या करने जा रहे हैं?

उदाहरण के लिए, यदि आप किसी सरणी की तरह लगने पर निहित मानों की गणना करने का इरादा रखते हैं या यदि यह एक हैश-टेबल के रूप में उपयोग की जा रही वस्तु है, तो निम्न कोड आपको चाहिए जो मिलता है (यह कोड बंद हो जाता है जब क्लोजर फ़ंक्शन अन्य कुछ भी लौटाता है "अपरिभाषित" की तुलना में। ध्यान दें कि यह 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" परीक्षण)

उपयोग के उदाहरण:

// 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] );
        }
    })
}

हालांकि जवाब दिलचस्प हो सकता है, यह वास्तव में सवाल के साथ कुछ नहीं करना है (और btw: के माध्यम से arrays पर iterating for..inखराब है [tm])
Christoph

@ क्रिसटोफ - निश्चित रूप से यह करता है। यह तय करने के लिए कुछ कारण होना चाहिए कि क्या कुछ ऐरे है: क्योंकि आप मूल्यों के साथ कुछ करना चाहते हैं। सबसे विशिष्ट चीजें (मेरे कोड में, कम से कम) मैप में फिल्टर, खोज, या अन्यथा डेटा को रूपांतरित करने के लिए हैं। उपरोक्त कार्य ठीक यही करता है: यदि पारित की गई चीज़ों में ऐसे तत्व होते हैं जो इससे अधिक पुनरावृत्त हो सकते हैं, तो यह उनके ऊपर पुनरावृत्ति करता है। यदि नहीं, तो यह कुछ नहीं करता है और हानिरहित रूप से अपरिभाषित रिटर्न देता है।
जेम्स हगार्ड

@Christoph - क्यों के साथ arrays पर iterating है। आप सरणियों और / या हैशटेबल्स (ऑब्जेक्ट्स) पर और कैसे पुनरावृति करेंगे?
जेम्स हगार्ड

1
@ नाम: for..inवस्तुओं के असंख्य गुणों पर आधारित; आपको सरणियों के साथ इसका उपयोग नहीं करना चाहिए क्योंकि: (1) यह धीमा है; (2) यह आदेश के संरक्षण की गारंटी नहीं है; (3) इसमें ऑब्जेक्ट या उसके किसी भी प्रोटोटाइप में सेट उपयोगकर्ता-परिभाषित संपत्ति शामिल होगी क्योंकि ES3 में DontEnum विशेषता सेट करने का कोई तरीका शामिल नहीं है; ऐसे अन्य मुद्दे हो सकते हैं जिनसे मेरा दिमाग फिसल गया हो
क्रिस्टोफ

1
@Christoph - दूसरी ओर, (।;) का उपयोग विरल सरणियों के लिए ठीक से काम नहीं करेगा और यह ऑब्जेक्ट गुणों को प्रदर्शित नहीं करेगा। # 3 आपके द्वारा उल्लिखित कारण के कारण ऑब्जेक्ट के लिए बुरा रूप माना जाता है। दूसरी ओर, आप SO प्रदर्शन के संबंध में सही हैं: for..in 1M तत्व सरणी पर (;;) की तुलना में ~ 36x धीमा है। वाह। दुर्भाग्य से, हमारे मुख्य उपयोग के मामले पर लागू नहीं होता है, जो ऑब्जेक्ट प्रॉपर्टीज (हैशटेबल्स) को प्रदर्शित करता है।
जेम्स हगार्ड

1

यदि आप CouchDB (स्पाइडरमोनकी) में ऐसा कर रहे हैं तो उपयोग करें

Array.isArray(array)

के रूप में array.constructor === Arrayया array instanceof Arrayकाम नहीं करते। का उपयोग कर array.toString() === "[object Array]"काम करता है, लेकिन तुलना में बहुत नीरस लगता है।


यह Node.js और ब्राउज़रों में भी काम करता है, न कि केवल CouchDB: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
कार्ल विल्बर


0

W3school पर एक उदाहरण है जो काफी मानक होना चाहिए।

यह जाँचने के लिए कि एक चर एक सरणी है, वे इसके समान कुछ का उपयोग करते हैं

function arrayCheck(obj) { 
    return obj && (obj.constructor==Array);
}

Chrome, Firefox, Safari, यानी 7 पर परीक्षण किया गया


constructorप्रकार की जाँच के लिए उपयोग करना imo बहुत भंगुर है; इसके बजाय सुझाए गए विकल्पों में से एक का उपयोग करें
क्रिस्टोफ

आप ऐसा क्यों सोचते हैं? भंगुर के बारे में?
कामारेई

@Kamarey: constructorप्रोटोटाइप ऑब्जेक्ट का एक नियमित डोनटेन गुण है; यह अंतर्निहित प्रकारों के लिए एक समस्या नहीं हो सकती है जब तक कोई भी कुछ भी बेवकूफ नहीं करता है, लेकिन उपयोगकर्ता द्वारा परिभाषित प्रकारों के लिए यह आसानी से हो सकता है; मेरी सलाह: हमेशा उपयोग करें instanceof, जो प्रोटोटाइप-चेन की जांच करता है और उन गुणों पर भरोसा नहीं करता है जिन्हें मनमाने ढंग से ओवरराइट किया जा सकता है
क्रिस्टोफ

1
धन्यवाद, यहाँ एक और स्पष्टीकरण मिला: thinkweb2.com/projects/prototype/…
कामारे

यह विश्वसनीय नहीं है, क्योंकि ऐरे ऑब्जेक्ट को कस्टम ऑब्जेक्ट के साथ ओवर-लिखा जा सकता है।
जोश स्टोडोला

-2

इस फ़ंक्शन के सर्वोत्तम शोध और चर्चा किए गए संस्करणों में से एक PHPJS साइट पर पाया जा सकता है । आप पैकेज से लिंक कर सकते हैं या आप सीधे फ़ंक्शन पर जा सकते हैं । मैं जावास्क्रिप्ट में PHP कार्यों के अच्छी तरह से निर्मित समकक्षों के लिए साइट की अत्यधिक अनुशंसा करता हूं।


-2

कंस्ट्रक्टरों के बराबर पर्याप्त संदर्भ नहीं। कभी-कभी उनके पास निर्माणकर्ता के अलग-अलग संदर्भ होते हैं। इसलिए मैं उनमें से स्ट्रिंग निरूपण का उपयोग करता हूं।

function isArray(o) {
    return o.constructor.toString() === [].constructor.toString();
}

द्वारा मूर्ख{constructor:{toString:function(){ return "function Array() { [native code] }"; }}}
बरगी

-4

Array.isArray(obj)द्वारा प्रतिस्थापित करेंobj.constructor==Array

नमूने:

Array('44','55').constructor==Array सही लौटें (IE8 / Chrome)

'55'.constructor==Array झूठा लौटें (IE8 / Chrome)


3
आप एक भयानक से सही फ़ंक्शन को क्यों बदलेंगे?
बरगी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.