JSLint त्रुटि 'के लिए शरीर का क्या मतलब है अगर एक' में लिपटा जाना चाहिए 'मतलब है?


242

मैंने अपनी एक जावास्क्रिप्ट फाइल पर JSLint का इस्तेमाल किया । यह त्रुटि फेंक दिया:

for( ind in evtListeners ) {

लाइन 41 समस्या 9 पर समस्या: प्रोटोटाइप में से अवांछित गुणों को फ़िल्टर करने के लिए एक के शरीर को एक स्टेटमेंट में लपेटा जाना चाहिए।

इसका क्या मतलब है?


5
डिफ़ॉल्ट रूप से 'इनहेरिट किए गए गुणों के साथ-साथ पुनरावृत्त करता है। आमतौर पर, शरीर को if (evtListeners.hasOwnProperty(ind))केवल अपने (गैर-विरासत वाले) गुणों के लिए प्रसंस्करण को सीमित करने के लिए लपेटा जाता है। फिर भी, कुछ मामलों में आप वास्तव में विरासत में मिली संपत्ति सहित सभी संपत्तियों पर पुनरावृति करना चाहते हैं। उस स्थिति में, JSLint लूप बॉडी को एक स्टेटमेंट में लपेटने के लिए बाध्य करता है, ताकि यह तय किया जा सके कि आपको कौन से गुण चाहिए। यह काम करेगा और JSlint को खुश करेगा: if (evtListeners[ind] !== undefined)
xorcus

1
अधिकांश उत्तर पुराने हैं। एक अद्यतन समाधान stackoverflow.com/a/10167931/3138375
eli-bd

जवाबों:


430

सबसे पहले, एक सरणी पर गणना करने के लिए लूप का उपयोग कभी न करें for in। कभी नहीँ। अच्छे पुराने का उपयोग करें for(var i = 0; i<arr.length; i++)

इसके पीछे का कारण निम्नलिखित है: जावास्क्रिप्ट में प्रत्येक वस्तु का एक विशेष क्षेत्र है जिसे कहा जाता है prototype। उस फ़ील्ड में जो कुछ भी आप जोड़ते हैं, वह उस प्रकार की प्रत्येक वस्तु पर उपलब्ध होने वाला है। मान लीजिए कि आप चाहते हैं कि सभी सरणियों में एक शांत नया फ़ंक्शन हो, जो filter_0कि जीरो को फ़िल्टर करेगा।

Array.prototype.filter_0 = function() {
    var res = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i] != 0) {
            res.push(this[i]);
        }
    }
    return res;
};

console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]

यह वस्तुओं का विस्तार करने और नए तरीकों को जोड़ने का एक मानक तरीका है। बहुत सारे पुस्तकालय ऐसा करते हैं। हालाँकि, आइए देखें कि for inअब कैसे काम करता है:

var listeners = ["a", "b", "c"];
for (o in listeners) {
    console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0

क्या तुम देखते हो? यह अचानक सोचता है कि फ़िल्टर_0 एक और सरणी सूचकांक है। बेशक, यह वास्तव में एक संख्यात्मक सूचकांक नहीं है, लेकिन for inवस्तु क्षेत्रों के माध्यम से गणना करता है, न कि केवल संख्यात्मक सूचकांक। इसलिए हम अब हर संख्यात्मक सूचकांक के माध्यम से गणना कर रहे हैं और filter_0 । लेकिन filter_0किसी विशेष सरणी ऑब्जेक्ट का क्षेत्र नहीं है, प्रत्येक सरणी ऑब्जेक्ट में अब यह गुण है।

सौभाग्य से, सभी वस्तुओं की एक hasOwnPropertyविधि होती है, जो यह जांचती है कि क्या यह क्षेत्र वास्तव में स्वयं वस्तु का है या यदि यह केवल प्रोटोटाइप श्रृंखला से विरासत में मिला है और इस प्रकार उस प्रकार की सभी वस्तुओं से संबंधित है।

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}
 //prints:
 //  0
 //  1
 //  2

ध्यान दें, हालांकि यह कोड सरणियों के लिए अपेक्षित के रूप में काम करता है, आपको कभी भी, कभी नहीं , उपयोग for inऔर for each inसरणियों के लिए करना चाहिए । याद रखें कि for inकिसी ऑब्जेक्ट के फ़ील्ड्स को एनुमरेट करता है, न कि सरणी इंडेक्स या वैल्यूज़।

var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}

 //prints:
 //  0
 //  1
 //  2
 //  happy

43
आपको for inसरणियों पर पुनरावृति करने के लिए उपयोग नहीं करना चाहिए क्योंकि भाषा उस आदेश को नहीं जोड़ती है जिसमें for inकिसी सरणी पर गणना की जाएगी। यह संख्यात्मक क्रम में नहीं हो सकता है। इसके अलावा, यदि आप `के लिए` (i = 0; i <array.length; i ++) शैली का उपयोग करते हैं, तो आप यह सुनिश्चित कर सकते हैं कि आप केवल क्रमिक संख्यात्मक सूचकांक क्रमबद्ध कर रहे हैं , और कोई अल्फ़ान्यूमेरिक गुण नहीं।
ब्रेटन

धन्यवाद! मैं इसे एक संदर्भ के रूप में सहेजूंगा।
nyuszika7h

मैंने अपने आप को इस उत्तर को फिर से देखते हुए पाया क्योंकि मुझे यकीन था कि JSLint का यह हिस्सा टूट गया था। मेरे पास कोड था जो मोटे तौर पर: (श्रोताओं में ओ) {अगर (श्रोता.हासऑनप्रोसेसर (आई)) {कंसोल.लॉग (ओ); }} समस्या यह है कि मेरे पास एक बग था, मैं चर नामों को ओ पर स्विच करूँगा और एक संदर्भ याद किया। JSLint यह सुनिश्चित करने के लिए पर्याप्त स्मार्ट है कि आप सही ऑब्जेक्ट पर सही प्रॉपर्टी के लिए hasOwnProperty की जाँच कर रहे हैं।
आकर्षित किया

12
हालाँकि, किसी वस्तु की संपत्ति पर पुनरावृति के लिए ठीक है। ओपी ने कभी नहीं कहा कि एक एरियर के लिए आवेदन किया गया था। HasOwnProperty सबसे अच्छा अभ्यास है, हालांकि ऐसे मामले हैं जहां आप इसे नहीं चाहते हैं - उदाहरण के लिए यदि कोई वस्तु किसी और को विस्तारित करती है, और आप दोनों वस्तुओं और 'माता-पिता' के गुणों को सूचीबद्ध करना चाहते हैं।
गेटोफ्रिट्स

3
मुझे लगता है कि लोगों को for-inलूप से दूर करने के बजाय (जो कि कमाल के हैं), हमें उन्हें शिक्षित करना चाहिए कि वे कैसे काम करते हैं (इस जवाब में ठीक से किया है) और उन्हें परिचय दें Object.defineProperty()ताकि वे बिना किसी चीज को तोड़ने के अपने प्रोटोटाइप को सुरक्षित रूप से बढ़ा सकें। संयोग से, देशी वस्तुओं के प्रोटोटाइप को बढ़ाए बिना नहीं किया जाना चाहिए Object.defineProperty
रॉबर्ट रॉसमैन

87

डगलस क्रॉकफोर्ड, jslint के लेखक ने इस मुद्दे के बारे में कई बार लिखा है (और बोला है)। उनकी वेबसाइट के इस पृष्ठ पर एक खंड है जो इसे कवर करता है:

कथन के लिए

बयानों के वर्ग के लिए निम्न रूप होना चाहिए:

for (initialization; condition; update) {
    statements
}

for (variable in object) {
    if (filter) {
        statements
    } 
}

पहले फॉर्म को सरणियों के साथ और पूर्ववर्ती संख्या के पुनरावृत्तियों के छोरों के साथ उपयोग किया जाना चाहिए।

दूसरा रूप वस्तुओं के साथ उपयोग किया जाना चाहिए। ध्यान रखें कि ऑब्जेक्ट के प्रोटोटाइप में जोड़े जाने वाले सदस्यों को एन्यूमरेशन में शामिल किया जाएगा। वस्तु के वास्तविक सदस्यों को अलग करने के लिए hasOwnProperty विधि का उपयोग करके रक्षात्मक रूप से कार्यक्रम करना बुद्धिमानी है:

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}

क्रॉकफोर्ड के पास YUI थिएटर पर एक वीडियो श्रृंखला भी है जहां वह इस बारे में बात करते हैं। जावास्क्रिप्ट के बारे में वीडियो / बातचीत की क्रॉकफ़ोर्ड श्रृंखला को अवश्य देखना चाहिए कि क्या आप जावास्क्रिप्ट के बारे में थोड़ा गंभीर हैं।


21

खराब: (jsHint एक त्रुटि फेंक देगा)

for (var name in item) {
    console.log(item[name]);
}

अच्छा:

for (var name in item) {
  if (item.hasOwnProperty(name)) {
    console.log(item[name]);
  }
}

8

वावा का जवाब निशान पर है। यदि आप jQuery का उपयोग करते हैं, तो $.each()फ़ंक्शन इस बात का ध्यान रखता है, इसलिए इसका उपयोग करना अधिक सुरक्षित है।

$.each(evtListeners, function(index, elem) {
    // your code
});

5
यदि प्रदर्शन यहाँ कोई विचार कर रहा है, तो मैं कच्चे लूप से दूर होने पर $.each(या अंडरस्कोर। जेएस _.each) का उपयोग करने की सलाह नहीं forदूंगा। jsperf में कुछ आंखें खोलने वाले तुलनात्मक परीक्षण हैं जो चलने लायक हैं।
निकब

3
यह ( jsperf.com/each-vs-each-vs-for-in/3 ) अधिक यथार्थवादी है क्योंकि यह मूल प्रोटो फिल्टर को काम में
लेता है

7

@all - जावास्क्रिप्ट में सब कुछ एक वस्तु () है, इसलिए "केवल वस्तुओं पर इसका उपयोग करना" जैसे कथन थोड़े भ्रामक हैं। इसके अलावा जावास्क्रिप्ट दृढ़ता से टाइप नहीं किया जाता है ताकि 1 == "1" सही हो (हालांकि 1 === "1" नहीं है, क्रॉकफोर्ड इस पर बड़ा है)। जब जेएस में सरणियों की प्रोग्रोमैटिक अवधारणा की बात आती है, तो परिभाषा में टाइपिंग महत्वपूर्ण है।

@ बर्टन - शब्दावली तानाशाह होने की जरूरत नहीं; "साहचर्य सरणी", "शब्दकोश", "हैश", "ऑब्जेक्ट", ये प्रोग्रामिंग अवधारणाएं सभी जेएस में एक संरचना पर लागू होती हैं। यह नाम (कुंजी, सूचकांक) मूल्य जोड़े हैं, जहां मूल्य किसी भी अन्य वस्तु हो सकता है (तार भी वस्तुएं हैं)

तो, new Array()जैसा है वैसा ही है[]

new Object() के समान है {}

var myarray = [];

एक संरचना बनाता है जो प्रतिबंध के साथ एक सरणी है जो सभी अनुक्रमित (उर्फ कुंजी) एक पूरी संख्या होनी चाहिए। यह .push () के माध्यम से नए अनुक्रमित के ऑटो असाइन करने की भी अनुमति देता है

var myarray = ["one","two","three"];

वास्तव में के माध्यम से सबसे अच्छा निपटा है for(initialization;condition;update){

लेकिन क्या बारे में:

var myarray = [];
myarray[100] = "foo";
myarray.push("bar");

इसे इस्तेमाल करे:

var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

शायद एक सरणी का सबसे अच्छा उपयोग नहीं है, लेकिन सिर्फ एक उदाहरण है कि चीजें हमेशा स्पष्ट नहीं होती हैं।

यदि आप अपनी चाबियाँ जानते हैं, और निश्चित रूप से यदि वे पूरी संख्या में नहीं हैं, तो संरचना विकल्प की तरह आपका एकमात्र सरणी ऑब्जेक्ट है।

var i, myarray= {
   "first":"john",
   "last":"doe",
   100:"foo",
   150:"baz"
};
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

"केवल वस्तुओं पर इसका उपयोग करें" का अर्थ है इसका उपयोग एरेस या किसी अन्य चीज़ पर न करें जो वस्तु का विस्तार करता है, अन्यथा, जैसा कि आप बताते हैं, यह बहुत मूर्खतापूर्ण होगा क्योंकि सब कुछ वस्तु का विस्तार करता है
जुआन मेंडेस

'' साहचर्य सरणी '', '' शब्दकोष '', '' हैश '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '': ये '' शब्दावलियाँ, सभी शब्द '' जेएस '' '' '' '' '' '' '' '' ऐंसेशनल ऐरे '' '' '' '' '' 'ऐंसेशनल ऐरे' '' '' '' '' '' 'ऐरेक्सेशनल ऐरे' '' '' '' '' '' '' 'ऐंसेशनल ऐरे' '' '' '' '' 'ऐरेक्सेशनल ऐरे' '' '' '' '' 'ऐक्सेसिव ऐरे' '' '' '' '' से संबंधित किसी भी संरचना पर लागू होते हैं। नहीं, वे अलग-अलग भाषाओं से अलग-अलग अवधारणाएं हैं, एक-दूसरे के साथ समानताएं हैं । लेकिन अगर आप यह मानकर चलते हैं कि वे / बिल्कुल समान हैं / और उसी तरह से उपयोग किए जाने वाले हैं, तो समान उद्देश्यों के लिए, आप स्वयं को कुछ ऐसी मूर्खतापूर्ण गलतियाँ करने से रोक रहे हैं जिनसे आप कम अनभिज्ञ हो सकते हैं कि भाषा कैसे हो आप कामों का उपयोग कर रहे हैं।
ब्रेटन

2

निश्चित रूप से यह कहना थोड़ा अतिवादी है

... एक सरणी पर गणना करने के लिए लूप में कभी भी उपयोग न करें। कभी नहीँ। अच्छे पुराने का उपयोग करें (var i = 0; i <arr.length; i ++)

?

यह डगलस क्रॉकफोर्ड अर्क में अनुभाग को उजागर करने के लायक है

... दूसरा रूप वस्तुओं के साथ इस्तेमाल किया जाना चाहिए ...

यदि आपको एक सहयोगी सरणी (उर्फ हैशटेबल / शब्दकोश) की आवश्यकता होती है, जहां संख्यात्मक रूप से अनुक्रमित के बजाय कुंजी का नाम दिया जाता है, तो आपको इसे ऑब्जेक्ट के रूप में लागू करना होगा, जैसे var myAssocArray = {key1: "value1", key2: "value2"...};

इस मामले में myAssocArray.lengthअशक्त हो जाएगा (क्योंकि इस वस्तु में 'लंबाई' संपत्ति नहीं है), और आपके पास i < myAssocArray.lengthआपको बहुत दूर नहीं मिलेगा। अधिक से अधिक सुविधा प्रदान करने के अलावा, मैं कई स्थितियों में प्रदर्शन लाभ की पेशकश करने के लिए साहचर्य सरणियों की अपेक्षा करूंगा, क्योंकि सरणी कुंजियां उपयोगी गुण हो सकती हैं (यानी एक सरणी सदस्य की आईडी संपत्ति या नाम), जिसका अर्थ है कि आपको लंबे समय तक चलना नहीं है। सरणी बार-बार मूल्यांकन कर रही है कि क्या कथन आपके द्वारा किए गए सरणी प्रविष्टि को खोजने के लिए है।

वैसे भी, JSLint त्रुटि संदेशों की व्याख्या के लिए भी धन्यवाद, मैं अब 'myOad सहसंयोजक सरणियों के माध्यम से interting करते समय' isOwnProperty 'चेक का उपयोग करूँगा!


1
आप गहराई से भ्रमित हैं। जावास्क्रिप्ट में "साहचर्य सरणियों" जैसी कोई चीज नहीं है। यह कड़ाई से एक php अवधारणा है।
ब्रेटन

यह सच है कि इन वस्तुओं के पास कोई lengthसंपत्ति नहीं है , लेकिन आप इसे दूसरे तरीके से कर सकते हैं:var myArr = []; myArr['key1'] = 'hello'; myArr['key2'] = 'world';
nyuszika7h

3
@ Nyuszika7H यह गलत तरीका है। यदि आपको पूर्णांक अनुक्रमित सरणी की आवश्यकता नहीं है, तो आपको उपयोग नहीं करना चाहिए var myArr = [], यह var myArr = {}PHP में होना चाहिए वे एक ही चीज हैं, लेकिन जेएस में नहीं।
जुआन मेंडेस

साहचर्य "सरणी" एक सरणी नहीं है।
विंसेंट मैकनाब


0

सिर्फ / के लिए / $ के विषय पर जोड़ने के लिए। प्रत्येक के लिए, मैंने $ .each बनाम का उपयोग करने के लिए एक jsperf परीक्षण मामला जोड़ा: http://jsperf.com/each-vs-for-in/2

विभिन्न ब्राउज़र / संस्करण इसे अलग तरीके से संभालते हैं, लेकिन लगता है कि $ .each और सीधे बाहर के लिए सबसे सस्ता विकल्प प्रदर्शन-वार हैं।

यदि आप एक सहयोगी सरणी / वस्तु के माध्यम से पुनरावृत्ति करने के लिए उपयोग कर रहे हैं, तो यह जानकर कि आप क्या कर रहे हैं और बाकी सब कुछ अनदेखा कर रहे हैं, यदि आप jQuery का उपयोग करते हैं, तो बस .each का उपयोग करें। आप जो जानते हैं वह अंतिम तत्व होना चाहिए)

यदि आप इसमें प्रत्येक प्रमुख जोड़ी के साथ कुछ करने के लिए किसी सरणी के माध्यम से पुनरावृत्ति कर रहे हैं, तो आपको hasOwnProperty विधि का उपयोग करना चाहिए यदि आप jQuery का उपयोग नहीं करते हैं, और यदि आप jQuery का उपयोग करते हैं तो $ .each का उपयोग करें।

हमेशा उपयोग करें for(i=0;i<o.length;i++)यदि आपको एक साहचर्य सरणी की आवश्यकता नहीं है, ... lol chrome ने 97% तेजी से प्रदर्शन किया है या उसके लिए$.each

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