टी एल; डॉ
लेकिन वहाँ बहुत अधिक का पता लगाने के लिए, पर पढ़ें ...
जावास्क्रिप्ट में सरणियों और सरणी जैसी वस्तुओं के माध्यम से लूपिंग के लिए शक्तिशाली शब्दार्थ है। मैंने उत्तर को दो भागों में विभाजित किया है: वास्तविक सरणियों के लिए विकल्प, और उन चीजों के लिए विकल्प जो सिर्फ सरणी हैं - जैसे कि argumentsवस्तु, जैसे अन्य पुनरावृत्त वस्तुएं (ES2015 +), DOM संग्रह, और इसी तरह।
मैं जल्दी से ध्यान देता हूं कि आप ES5 इंजन का उपयोग कर सकते हैं , यहां तक कि ES5 इंजन पर भी, ES2015 को ES5 पर ट्रांसप्लान कर सकते हैं। अधिक के लिए "ES2015 ट्रांसपिलिंग" / "ईएस 6 ट्रांसपिलिंग" खोजें ...
ठीक है, चलो हमारे विकल्प देखें:
वास्तविक एरे के लिए
आपके पास ECMAScript 5 ("ES5") में तीन विकल्प हैं , जो इस समय सबसे व्यापक रूप से समर्थित है, और ECMAScript 2015 ("ES2015", "ES6") में दो और जोड़े गए हैं :
- उपयोग
forEachऔर संबंधित (ES5 +)
- एक साधारण
forलूप का उपयोग करें
- सही ढंग से उपयोग करें
for-in
- का उपयोग करें
for-of(एक iterator निहितार्थ का उपयोग करें ) (ES2015 +)
- स्पष्ट रूप से एक इटरेटर का उपयोग करें (ES2015 +)
विवरण:
1. उपयोग forEachऔर संबंधित
किसी भी अस्पष्ट-आधुनिक वातावरण में (इसलिए, IE8 नहीं) जहां आपके पास ArrayES5 द्वारा जोड़ी गई सुविधाओं तक पहुंच है (सीधे या पॉलीफिल्स का उपयोग करके), आप उपयोग कर सकते हैं forEach( spec| MDN):
var a = ["a", "b", "c"];
a.forEach(function(entry) {
console.log(entry);
});
forEachकॉलबैक फ़ंक्शन को स्वीकार करता है और वैकल्पिक रूप से, thisउस कॉलबैक को कॉल करते समय उपयोग करने के लिए एक मान (ऊपर उपयोग नहीं किया गया)। कॉलबैक को सरणी में प्रत्येक प्रविष्टि के लिए कहा जाता है, आदेश में, विरल सरणियों में गैर-मौजूद प्रविष्टियों को लंघन। हालाँकि मैंने ऊपर केवल एक तर्क का उपयोग किया था, कॉलबैक को तीन के साथ कहा जाता है: प्रत्येक प्रविष्टि का मूल्य, उस प्रविष्टि का सूचकांक, और उस सरणी का संदर्भ जो आप अपने कार्य से पहले ही इसे संभाल नहीं पा रहे हैं )।
जब तक आप IE8 जैसे अप्रचलित ब्राउज़रों का समर्थन नहीं कर रहे हैं (जो NetApps सितंबर 2016 में इस लेखन के रूप में केवल 4% से अधिक बाजार हिस्सेदारी पर दिखाता है), तो आप forEachबिना शर्म किए सामान्य रूप से सामान्य वेब पेज में उपयोग कर सकते हैं । यदि आपको अप्रचलित ब्राउज़रों का समर्थन करने की आवश्यकता है, तो shimming / polyfilling forEachआसानी से किया जाता है (कई विकल्पों के लिए "es5 शिम" की खोज करें)।
forEach लाभ यह है कि आपको अनुक्रमणिका और मूल्य चर को घोषित दायरे में घोषित करने की आवश्यकता नहीं है, क्योंकि वे पुनरावृत्ति फ़ंक्शन के तर्क के रूप में आपूर्ति किए जाते हैं, और इसलिए केवल उस पुनरावृत्ति के लिए अच्छी तरह से scoped।
यदि आप प्रत्येक सरणी प्रविष्टि के लिए फ़ंक्शन कॉल करने के रनटाइम लागत के बारे में चिंतित हैं, तो मत बनो; विवरण ।
इसके अतिरिक्त, forEach"उन सभी के माध्यम से लूप" फ़ंक्शन है, लेकिन ES5 ने कई अन्य उपयोगी परिभाषित किए हैं "अपने तरीके से सरणी के माध्यम से काम करें और" कार्य करें, जिनमें शामिल हैं:
every(कॉलबैक रिटर्न falseया किसी चीज़ को पहली बार लूप करना बंद कर देता है )
some(कॉलबैक रिटर्न trueया कुछ सच होने पर पहली बार लूप बंद करना)
filter(उन तत्वों को शामिल करता है, जिनमें फ़िल्टर फ़ंक्शन लौटता है trueऔर जहाँ वह वापस लौटता है, उन्हें छोड़ता है false)
map (कॉलबैक द्वारा दिए गए मानों से एक नई सरणी बनाता है)
reduce (कॉलबैक को बार-बार कॉल करके, पिछले मानों में पास करके एक मान बनाता है; विवरण के लिए युक्ति देखें; एक सरणी की सामग्री और कई अन्य चीजों के लिए उपयोगी है)
reduceRight(जैसे reduce, लेकिन आरोही क्रम के बजाय अवरोही में काम करता है)
2. एक साधारण forलूप का उपयोग करें
कभी-कभी पुराने तरीके सबसे अच्छे होते हैं:
var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
console.log(a[index]);
}
यदि लूप के दौरान ऐरे की लंबाई नहीं बदलेगी, और यह प्रदर्शन-संवेदनशील कोड (असंभावित) में है, तो सामने की ओर लंबाई को पकड़े हुए थोड़ा अधिक जटिल संस्करण एक छोटा सा तेज़ हो सकता है :
var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
console.log(a[index]);
}
और / या पीछे की गिनती:
var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
console.log(a[index]);
}
लेकिन आधुनिक जावास्क्रिप्ट इंजन के साथ, यह दुर्लभ है कि आपको रस के अंतिम बिट को बाहर निकालने की आवश्यकता है।
ES2015 और उच्चतर में, आप अपने सूचकांक और मान को forलूप में स्थानीय बना सकते हैं :
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
console.log(index, value);
}
//console.log(index); // would cause "ReferenceError: index is not defined"
//console.log(value); // would cause "ReferenceError: value is not defined"
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
console.log(index, value);
}
try {
console.log(index);
} catch (e) {
console.error(e); // "ReferenceError: index is not defined"
}
try {
console.log(value);
} catch (e) {
console.error(e); // "ReferenceError: value is not defined"
}
और जब आप ऐसा करते हैं, तो न केवल, valueबल्कि indexप्रत्येक लूप पुनरावृत्ति के लिए फिर से बनाया जाता है, जिसका अर्थ है लूप बॉडी में निर्मित क्लोजर उस विशिष्ट पुनरावृत्ति के लिए बनाए गए index(और value) का संदर्भ रखते हैं :
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
divs[index].addEventListener('click', e => {
console.log("Index is: " + index);
});
}
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
divs[index].addEventListener('click', e => {
console.log("Index is: " + index);
});
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
यदि आपके पास पाँच विभाग हैं, तो आपको "सूचकांक है: 0" यदि आपने पहले क्लिक किया है और "सूचकांक है: 4" यदि आपने अंतिम क्लिक किया है। यदि आप इसके बजाय उपयोग करते हैं तो यह काम नहीं करता varहै let।
3. सही ढंग से उपयोग करेंfor-in
आप लोगों से कहेंगे कि आप इसका इस्तेमाल करें for-in, लेकिन ऐसा नहीं for-inहै । किसी वस्तुfor-in के असंख्य गुणों के माध्यम से लूप्स , न कि किसी सरणी के अनुक्रमित। आदेश की गारंटी नहीं है , ES2015 (ES6) में भी नहीं। ES2015 + एक आदेश को गुण के माध्यम से परिभाषित करता है (के माध्यम से [[OwnPropertyKeys]], [[Enumerate]]और उन चीजों का उपयोग करता है जो उन्हें पसंद करते हैं Object.getOwnPropertyKeys), लेकिन यह परिभाषित नहीं किया कि for-inउस आदेश का पालन करेगा; ES2020, हालांकि किया। ( इस अन्य उत्तर में विवरण ।)
for-inकिसी सरणी पर केवल वास्तविक उपयोग के मामले हैं:
- यह बड़े पैमाने पर अंतराल के साथ एक विरल सरणियाँ है, या
- आप गैर-तत्व गुणों का उपयोग कर रहे हैं और आप उन्हें लूप में शामिल करना चाहते हैं
केवल उस पहले उदाहरण को देखते हुए: for-inयदि आप उचित सुरक्षा उपायों का उपयोग करते हैं, तो आप उन विरल सरणी तत्वों की यात्रा कर सकते हैं :
// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
if (a.hasOwnProperty(key) && // These checks are
/^0$|^[1-9]\d*$/.test(key) && // explained
key <= 4294967294 // below
) {
console.log(a[key]);
}
}
तीन जाँचों पर ध्यान दें:
वस्तु अपनी नहीं है यही कारण है कि खुद उस नाम (नहीं एक यह अपने प्रोटोटाइप से विरासत), और से संपत्ति
यह कुंजी सभी दशमलव अंक हैं (उदाहरण के लिए, सामान्य स्ट्रिंग रूप, वैज्ञानिक संकेतन नहीं), और
यह महत्वपूर्ण है कि जब किसी संख्या के लिए मजबूर किया जाता है, तो <= 2 ^ 32 - 2 (जो 4,294,967,294 है)। वह संख्या कहां से आती है? यह विनिर्देश में एक सरणी सूचकांक की परिभाषा का हिस्सा है । अन्य संख्याएँ (गैर-पूर्णांक, ऋणात्मक संख्याएँ, 2 ^ 32 - 2 से अधिक संख्याएँ) सरणी अनुक्रमणिका नहीं हैं। इसका कारण 2 ^ 32 - 2 है, जो कि सबसे बड़ी इंडेक्स वैल्यू को 2 ^ 32 - 1 से कम बनाता है , जो एक एरे का अधिकतम मूल्य lengthहो सकता है। (उदाहरण के लिए, एक सरणी की लंबाई 32-बिट अहस्ताक्षरित पूर्णांक में फिट होती है।) ( मेरे ब्लॉग पोस्ट पर एक टिप्पणी में इंगित करने के लिए RobG के लिए प्रॉप्स कि मेरा पिछला परीक्षण बिल्कुल सही नहीं था।)
आप निश्चित रूप से इनलाइन कोड नहीं करेंगे। आप एक उपयोगिता फ़ंक्शन लिखेंगे। शायद:
// Utility function for antiquated environments without `forEach`
var hasOwn = Object.prototype.hasOwnProperty;
var rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
var index;
for (var key in array) {
index = +key;
if (hasOwn.call(a, key) &&
rexNum.test(key) &&
index <= 4294967294
) {
callback.call(thisArg, array[key], index, array);
}
}
}
var a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";
sparseEach(a, function(value, index) {
console.log("Value at " + index + " is " + value);
});
4. for-of(इम्परेटर का उपयोग करें ) (ES2015 +) का उपयोग करें
ES2015 जोड़ा iterators जावास्क्रिप्ट को। पुनरावृत्तियों का उपयोग करने का सबसे आसान तरीका नया for-ofकथन है। यह इस तरह दिख रहा है:
const a = ["a", "b", "c"];
for (const val of a) {
console.log(val);
}
कवर के तहत, यह सरणी से एक पुनरावृत्ति प्राप्त करता है और इसके माध्यम से लूप करता है, इससे मान प्राप्त करता है। इसका उपयोग करने वाले समस्या के पास नहीं for-inहै, क्योंकि यह ऑब्जेक्ट (सरणी) द्वारा परिभाषित एक पुनरावृत्ति का उपयोग करता है, और सरणियों को परिभाषित करता है कि उनके पुनरावृत्तियों उनकी प्रविष्टियों के माध्यम से पुनरावृति करते हैं (उनके गुणों को नहीं)। for-inES5 के विपरीत , जिस क्रम में प्रविष्टियों का दौरा किया जाता है वह उनके अनुक्रमित का संख्यात्मक क्रम है।
5. स्पष्ट रूप से एक पुनरावृत्ति का उपयोग करें (ES2015 +)
कभी-कभी, आप इट्रेटर का उपयोग स्पष्ट रूप से करना चाह सकते हैं । आप यह भी कर सकते हैं, हालांकि, यह बहुत अधिक क्लिंकर है for-of। यह इस तरह दिख रहा है:
const a = ["a", "b", "c"];
const it = a.values();
let entry;
while (!(entry = it.next()).done) {
console.log(entry.value);
}
इटरेटर विनिर्देश में Iterator परिभाषा से मेल खाती एक वस्तु है। हर बार जब आप इसे कहते हैं, तो इसका nextतरीका एक नई परिणाम वस्तु देता है। परिणाम वस्तु में एक संपत्ति होती है, doneजो हमें बताती है कि क्या यह किया गया है, और valueउस पुनरावृत्ति के लिए एक संपत्ति है । ( doneवैकल्पिक है अगर यह होगा false, valueवैकल्पिक है अगर यह होगा undefined।)
valueइटरेटर के आधार पर भिन्नता का अर्थ ; एरियर्स समर्थन (कम से कम) तीन कार्य जो पुनरावृत्तियाँ लौटाते हैं:
values(): यह वही है जिसका मैंने ऊपर प्रयोग किया है। यह एक इटरेटर जहां प्रत्येक रिटर्न valueकि यात्रा के लिए सरणी प्रविष्टि है ( "a", "b", और "c"उदाहरण के पहले में)।
keys(): रिटर्न पुनरावर्तक जहां प्रत्येक valueकि यात्रा के लिए महत्वपूर्ण है (ताकि हमारे लिए aऊपर, कि हो सकता है "0", तो "1", तो "2")।
entries(): एक पुनरावृत्ति देता है जहाँ प्रत्येक उस पुनरावृत्ति के लिए valueएक सरणी है [key, value]।
एरे-लाइक ऑब्जेक्ट के लिए
वास्तविक सरणियों के अलावा, ऐसी सरणी- वस्तुएं भी हैं जिनके पास lengthसंख्यात्मक नाम के साथ एक संपत्ति और गुण हैं: NodeListउदाहरण, argumentsऑब्जेक्ट, आदि हम उनकी सामग्री के माध्यम से कैसे लूप करते हैं?
सरणियों के लिए ऊपर दिए गए किसी भी विकल्प का उपयोग करें
कम से कम कुछ, और संभवतः सबसे अधिक या यहां तक कि सभी, ऊपर दिए गए एरे दृष्टिकोण के समान एरे जैसी वस्तुओं पर समान रूप से लागू होते हैं:
उपयोग forEachऔर संबंधित (ES5 +)
विभिन्न कार्य Array.prototype"जानबूझकर सामान्य" हैं और आमतौर पर सरणी जैसी वस्तुओं पर Function#callया के माध्यम से उपयोग किया जा सकता है Function#apply। ( इस उत्तर के अंत में होस्ट-प्रदान की गई वस्तुओं के लिए कैविएट देखें , लेकिन यह एक दुर्लभ मुद्दा है।)
आप उपयोग करना चाहता था मान लीजिए forEachएक पर Nodeकी childNodesसंपत्ति। आप ऐसा करेंगे:
Array.prototype.forEach.call(node.childNodes, function(child) {
// Do something with `child`
});
यदि आप ऐसा करने जा रहे हैं, तो आप पुन: उपयोग के लिए एक चर में फ़ंक्शन संदर्भ की एक प्रति हड़पना चाहते हैं, जैसे:
// (This is all presumably in some scoping function)
var forEach = Array.prototype.forEach;
// Then later...
forEach.call(node.childNodes, function(child) {
// Do something with `child`
});
एक साधारण forलूप का उपयोग करें
जाहिर है, एक साधारण forलूप सरणी जैसी वस्तुओं पर लागू होता है।
सही ढंग से उपयोग करेंfor-in
for-inएक सरणी के साथ एक ही सुरक्षा उपायों के साथ सरणी जैसी वस्तुओं के साथ भी काम करना चाहिए; उपरोक्त # 1 पर होस्ट-प्रदान की गई वस्तुओं के लिए चेतावनी लागू हो सकती है।
का उपयोग करें for-of(एक iterator निहितार्थ का उपयोग करें ) (ES2015 +)
for-ofवस्तु (यदि कोई है) द्वारा प्रदान किए गए पुनरावृत्ति का उपयोग करता है । जिसमें होस्ट-प्रदत्त ऑब्जेक्ट शामिल हैं। उदाहरण के लिए, के लिए विनिर्देश NodeListसे querySelectorAllयात्रा का समर्थन करने के अद्यतन किया गया था। के लिए कल्पना HTMLCollectionसे getElementsByTagNameनहीं था।
स्पष्ट रूप से एक इटरेटर का उपयोग करें (ES2015 +)
# 4 देखें।
एक सच्ची सरणी बनाएँ
दूसरी बार, आप एक सरणी जैसी वस्तु को एक सच्चे सरणी में बदलना चाहते हैं। ऐसा करना आश्चर्यजनक रूप से आसान है:
sliceसरणियों की विधि का उपयोग करें
हम sliceसरणियों की विधि का उपयोग कर सकते हैं , जो ऊपर बताए गए अन्य तरीकों की तरह "जानबूझकर सामान्य" है और इसलिए इसका उपयोग सरणी जैसी वस्तुओं के साथ किया जा सकता है:
var trueArray = Array.prototype.slice.call(arrayLikeObject);
उदाहरण के लिए, यदि हम NodeListएक वास्तविक सरणी में बदलना चाहते हैं, तो हम ऐसा कर सकते हैं:
var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
होस्ट-प्रदान की गई वस्तुओं के लिए कैविएट देखें । विशेष रूप से, ध्यान दें कि यह IE8 और इससे पहले में विफल हो जाएगा, जो आपको होस्ट-प्रदान की गई वस्तुओं का उपयोग करने की अनुमति नहीं देता thisहै।
स्प्रेड सिंटैक्स ( ...) का उपयोग करें
जावास्क्रिप्ट इंजनों के साथ ES2015 के प्रसार सिंटैक्स का उपयोग करना भी संभव है जो इस सुविधा का समर्थन करते हैं। जैसे for-of, यह ऑब्जेक्ट द्वारा प्रदान किए गए पुनरावृत्ति का उपयोग करता है (पिछले अनुभाग में # 4 देखें):
var trueArray = [...iterableObject];
उदाहरण के लिए, यदि हम NodeListएक वास्तविक सरणी में बदलना चाहते हैं, तो प्रसार सिंटैक्स के साथ यह काफी सफल हो जाता है:
var divs = [...document.querySelectorAll("div")];
उपयोग Array.from
Array.from (कल्पना) | (MDN) (ES2015 +, लेकिन आसानी से पॉलीफ़िल्ड) एक सरणी जैसी ऑब्जेक्ट से एक सरणी बनाता है, वैकल्पिक रूप से पहले एक मैपिंग फ़ंक्शन के माध्यम से प्रविष्टियों को पास करना। इसलिए:
var divs = Array.from(document.querySelectorAll("div"));
या यदि आप दिए गए वर्ग के साथ तत्वों के टैग नामों की एक सरणी प्राप्त करना चाहते हैं, तो आप मैपिंग फ़ंक्शन का उपयोग करेंगे:
// Arrow function (ES2015):
var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
// Standard function (since `Array.from` can be shimmed):
var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
return element.tagName;
});
मेजबान प्रदान की वस्तुओं के लिए चेतावनी
यदि आप होस्ट-प्रदान की गई सरणी जैसी ऑब्जेक्ट्स (जावास्क्रिप्ट सूचियों और जावास्क्रिप्ट इंजन के बजाय ब्राउज़र द्वारा प्रदान की गई अन्य चीजें) के Array.prototypeसाथ फ़ंक्शंस का उपयोग करते हैं , तो आपको यह सुनिश्चित करने की ज़रूरत है कि होस्ट-प्रदान की गई वस्तु ठीक से व्यवहार करे । अधिकांश ठीक से व्यवहार करते हैं (अब), लेकिन यह परीक्षण करना महत्वपूर्ण है। कारण यह है कि आपके द्वारा अमूर्त संचालन के लिए एक ईमानदार जवाब देने के अधिकांश तरीकों का उपयोग आप मेजबान द्वारा प्रदान की गई वस्तु पर भरोसा करना चाहते हैं । इस लेखन के रूप में, ब्राउज़र इस का बहुत अच्छा काम करते हैं, लेकिन 5.1 कल्पना ने इस बात की अनुमति दी है कि मेजबान द्वारा प्रदान की गई वस्तु ईमानदार नहीं हो सकती है। यह big8.6.2 में है , उस खंड की शुरुआत के पास बड़ी तालिका के नीचे कई पैराग्राफ), जहाँ यह कहता है:Array.prototype[[HasProperty]]
होस्ट ऑब्जेक्ट इन आंतरिक तरीकों को किसी भी तरीके से लागू कर सकते हैं जब तक कि अन्यथा निर्दिष्ट न हो; उदाहरण के लिए, एक संभावना यह है कि [[Get]]और [[Put]]एक विशेष मेजबान वस्तु के लिए वास्तव में संपत्ति मूल्यों को प्राप्त करना और संग्रहीत करना है लेकिन [[HasProperty]]हमेशा गलत उत्पन्न करता है ।
(मैं ES2015 कल्पना में बराबर शब्दाडंबर नहीं मिल सकता है, लेकिन यह अभी भी मामला होने के लिए बाध्य कर रहा है।) फिर, यह के रूप में आम मेजबान प्रदान की [आधुनिक ब्राउज़रों में वस्तुओं सरणी की तरह लिख NodeListउदाहरण के लिए उदाहरणों,] कर संभाल [[HasProperty]]सही ढंग से, लेकिन यह परीक्षण करना महत्वपूर्ण है।)
forEachऔर सिर्फ नहींfor। जैसा कि कहा गया है, c # में यह थोड़ा अलग था, और