सवाल लूप के अंदर जावास्क्रिप्ट बंद - सरल व्यावहारिक उदाहरण


var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function() {          // and store them in funcs
    console.log("My value: " + i); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

यह यह आउटपुट करता है:

मेरा मूल्य: 3
  मेरा मूल्य: 3
  मेरा मूल्य: 3

जबकि मैं इसे आउटपुट करना चाहता हूं:

मेरा मूल्य: 0
  मेरा मूल्य: 1
  मेरा मूल्य: 2


वही समस्या तब होती है जब फ़ंक्शन चलाने में देरी ईवेंट श्रोताओं का उपयोग करके होती है:

var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {          // let's create 3 functions
  buttons[i].addEventListener("click", function() { // as event listeners
    console.log("My value: " + i);                  // each should log its value.
  });
}
<button>0</button><br>
<button>1</button><br>
<button>2</button>

... या असीमित कोड, उदा। वादे का उपयोग करना:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for(var i = 0; i < 3; i++){
  wait(i * 100).then(() => console.log(i)); // Log `i` as soon as each promise resolves.
}

इस मूल समस्या का समाधान क्या है?


2324
2018-04-15 06:06


मूल


आप सुनिश्चित हैं कि आप नहीं चाहते हैं funcs यदि आप संख्यात्मक सूचकांक का उपयोग कर रहे हैं, तो एक सरणी बनने के लिए? बिलकुल चौकन्ना। - DanMan
यह वास्तव में भ्रमित समस्या है। इस लेख इसे समझने में मेरी मदद करें। क्या यह दूसरों की भी मदद कर सकता है। - user3199690
एक और सरल और स्पष्टीकरण समाधान: 1) नेस्टेड फ़ंक्शंस उनके ऊपर "दायरे" तक पहुंच है; 2) ए समापन उपाय... "एक बंद एक पैरेंट फ़ंक्शन बंद होने के बावजूद, माता-पिता के दायरे तक पहुंचने वाला फ़ंक्शन होता है"। - Peter Krauss
बेहतर असुरक्षितता के लिए इस लिंक का संदर्भ लें javascript.info/tutorial/advanced-functions - Saurabh Ahuja
में ES6, परिवर्तनीय घोषित करने के लिए एक मामूली समाधान है मैं साथ में चलो, जो लूप के शरीर के लिए scoped है। - Tomas Nikodym


जवाब:


खैर, समस्या यह है कि चर i, आपके प्रत्येक अज्ञात कार्यों में, फ़ंक्शन के बाहर एक ही चर के लिए बाध्य है।

क्लासिक समाधान: क्लोजर

आप जो करना चाहते हैं वह फ़ंक्शन के बाहर एक अलग, अपरिवर्तनीय मान पर प्रत्येक फ़ंक्शन के भीतर चर को बाध्य करता है:

var funcs = [];

function createfunc(i) {
    return function() { console.log("My value: " + i); };
}

for (var i = 0; i < 3; i++) {
    funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

चूंकि जावास्क्रिप्ट में कोई ब्लॉक स्कोप नहीं है - केवल फ़ंक्शन स्कोप - फ़ंक्शन सृजन को एक नए फ़ंक्शन में लपेटकर, आप सुनिश्चित करते हैं कि "i" का मान आपके इरादे से बना रहता है।


2015 समाधान: प्रत्येक के लिए

अपेक्षाकृत व्यापक उपलब्धता के साथ Array.prototype.forEach कार्य (2015 में), यह ध्यान देने योग्य है कि उन परिस्थितियों में मुख्य रूप से मूल्यों की एक सरणी पर पुनरावृत्ति शामिल है, .forEach() प्रत्येक पुनरावृत्ति के लिए एक अलग बंद करने के लिए एक स्वच्छ, प्राकृतिक तरीका प्रदान करता है। यही है, मान लीजिए कि आपके पास मूल्यों (डीओएम संदर्भ, वस्तुएं, जो कुछ भी) शामिल हैं, और प्रत्येक तत्व के लिए विशिष्ट कॉलबैक सेट करने की समस्या उत्पन्न होती है, तो आप यह कर सकते हैं:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

विचार यह है कि कॉलबैक फ़ंक्शन के प्रत्येक आमंत्रण के साथ उपयोग किया जाता है .forEach लूप अपना बंद हो जाएगा। उस हैंडलर में पारित पैरामीटर पुनरावृत्ति के उस विशेष चरण के लिए विशिष्ट सरणी तत्व है। यदि इसका उपयोग एसिंक्रोनस कॉलबैक में किया जाता है, तो यह पुनरावृत्ति के अन्य चरणों में स्थापित किसी अन्य कॉलबैक से टकरा नहीं जाएगा।

यदि आप jQuery में काम करना चाहते हैं, तो $.each() समारोह आपको एक समान क्षमता देता है।


ईएस 6 समाधान: let

ईसीएमएस्क्रिप्ट 6 (ईएस 6), जावास्क्रिप्ट का नवीनतम संस्करण, अब कई सदाबहार ब्राउज़र और बैकएंड सिस्टम में लागू किया जा रहा है। जैसे ट्रांसपेलर भी हैं कोलाहल जो पुराने सिस्टम पर नई सुविधाओं के उपयोग की अनुमति देने के लिए ES6 से ES5 को परिवर्तित करेगा।

ES6 नया परिचय let तथा const कीवर्ड जो अलग से स्कॉप्ड हैं varआधारित चर उदाहरण के लिए, एक लूप में एक के साथ letआधारित सूचकांक, लूप के माध्यम से प्रत्येक पुनरावृत्ति का एक नया मूल्य होगा i जहां प्रत्येक मान लूप के अंदर स्कॉप्ड किया जाता है, इसलिए आपका कोड काम करेगा जैसा आप उम्मीद करते हैं। कई संसाधन हैं, लेकिन मैं अनुशंसा करता हूं 2ality की ब्लॉक-स्कोपिंग पोस्ट जानकारी का एक महान स्रोत के रूप में।

for (let i = 0; i < 3; i++) {
    funcs[i] = function() {
        console.log("My value: " + i);
    };
}

सावधान रहें, हालांकि, एज 14 समर्थन से पहले IE9-IE11 और एज let लेकिन उपरोक्त गलत प्राप्त करें (वे एक नया नहीं बनाते हैं i हर बार, तो ऊपर दिए गए सभी कार्य 3 लॉग करेंगे जैसे कि अगर हम इस्तेमाल करते हैं तो वे करेंगे var)। एज 14 आखिरकार यह सही हो जाता है।


1799
2018-04-15 06:18



नहीं है function createfunc(i) { return function() { console.log("My value: " + i); }; } अभी भी बंद है क्योंकि यह चर का उपयोग करता है i? - アレックス
दुर्भाग्यवश, यह उत्तर पुराना है और उपयोग करने के लिए कोई भी सही उत्तर नहीं देखेगा Function.bind() अब निश्चित रूप से बेहतर है, देखें stackoverflow.com/a/19323214/785541। - Wladimir Palant
@Wladimir: आपका सुझाव है कि .bind() है "सही उत्तर" सही नहीं है उनमें से प्रत्येक का अपना स्थान होता है। साथ में .bind() आप बिना बाध्य किए तर्कों को बांध नहीं सकते हैं this मूल्य। इसके अलावा आपको एक प्रति प्राप्त होती है i कॉल के बीच इसे म्यूट करने की क्षमता के बिना तर्क, जिसे कभी-कभी जरूरी है। तो वे उल्लेख करने के लिए नहीं, काफी अलग संरचनाएं हैं .bind() कार्यान्वयन ऐतिहासिक रूप से धीमा रहा है। निश्चित रूप से सरल उदाहरण में काम करेगा, लेकिन बंद करने के लिए बंद करना एक महत्वपूर्ण अवधारणा है, और यही सवाल था। - cookie monster
कृपया इन फॉर-रिटर्न फ़ंक्शन हैक्स का उपयोग करना बंद करें, [] .forEach या [] .map का उपयोग करें क्योंकि वे समान स्कोप चर का पुन: उपयोग करने से बचते हैं। - Christian Landgren
@ क्रिस्टियन लैंडग्रेन: यह केवल तभी उपयोगी है जब आप एक ऐरे को फिर से सक्रिय कर रहे हों। ये तकनीकें "हैक्स" नहीं हैं। वे आवश्यक ज्ञान हैं।


प्रयत्न:

var funcs = [];

for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

संपादित करें (2014):

व्यक्तिगत रूप से मुझे लगता है @ ऑस्ट उपयोग के बारे में अधिक हालिया जवाब .bind अब इस तरह की चीज करने का सबसे अच्छा तरीका है। लो-डैश / अंडरस्कोर भी है _.partial जब आपको जरूरत नहीं है या गड़बड़ करना चाहते हैं bindकी thisArg


340
2018-04-15 06:10



के बारे में कोई स्पष्टीकरण }(i)); ? - aswzen
@aswzen मुझे लगता है कि यह गुजरता है i तर्क के रूप में index समारोह में। - Jet Blue


एक और तरीका जिसका अभी तक उल्लेख नहीं किया गया है इसका उपयोग है Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

अद्यतन करें

जैसा कि @ स्क्विंट और @ मेकेदेव द्वारा इंगित किया गया है, आपको पहले लूप के बाहर फ़ंक्शन बनाने और लूप के भीतर परिणामों को बाध्य करके बेहतर प्रदर्शन मिलता है।

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}


310
2017-10-11 16:41



मैं इन दिनों भी यही करता हूं, मुझे लो-डैश / अंडरस्कोर भी पसंद है _.partial - Bjorn Tipling
.bind() ECMAScript 6 सुविधाओं के साथ काफी हद तक अप्रचलित हो जाएगा। इसके अलावा, यह वास्तव में प्रति पुनरावृत्ति के दो कार्य बनाता है। सबसे पहले अज्ञात, फिर से उत्पन्न एक .bind()। इसके बाद लूप के बाहर इसे बेहतर बनाने के लिए बेहतर उपयोग किया जाएगा .bind() अंदर
क्या यह जेएसएचआईंट ट्रिगर नहीं करता है - लूप के भीतर फ़ंक्शन न करें। ? मैं इस पथ को भी नीचे चला गया लेकिन कोड गुणवत्ता उपकरण चलाने के बाद यह कोई नहीं है .. - mekdev
@squint @mekdev - आप दोनों सही हैं। मेरा प्रारंभिक उदाहरण यह दिखाने के लिए जल्दी से लिखा गया था कि कैसे bind प्रयोग किया जाता है। मैंने आपके सुझावों के अनुसार एक और उदाहरण जोड़ा है। - Aust
मुझे लगता है कि दो ओ (एन) लूप पर गणना को बर्बाद करने के बजाय, बस (var i = 0; i <3; i ++) {log.call (यह, i); } - user2290820


एक का उपयोग करना तत्काल-सम्मिलित समारोह अभिव्यक्ति, एक सूचकांक चर संलग्न करने के लिए सबसे सरल और सबसे पठनीय तरीका:

for (var i = 0; i < 3; i++) {

    (function(index) {
        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value: $.ajax({});
    })(i);

}

यह इटरेटर भेजता है i अज्ञात कार्य में जिसमें हम परिभाषित करते हैं index। यह एक बंदरगाह बनाता है, जहां चर i IIFE के भीतर किसी भी एसिंक्रोनस कार्यक्षमता में बाद में उपयोग के लिए सहेजा जाता है।


234
2017-10-11 18:23



आगे कोड पठनीयता के लिए और जिसके बारे में भ्रम से बचने के लिए i क्या है, मैं फ़ंक्शन पैरामीटर का नाम बदलूंगा index। - Kyle Falconer
सरणी को परिभाषित करने के लिए आप इस तकनीक का उपयोग कैसे करेंगे funcs मूल प्रश्न में वर्णित है? - Nico
@Nico मूल प्रश्न में दिखाए गए जैसा ही है, सिवाय इसके कि आप इसका उपयोग करेंगे index के बजाय i। - JLRishe
@JLRishe var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); } - Nico
@ निको ओपी के विशेष मामले में, वे सिर्फ संख्याओं पर फिर से चल रहे हैं, इसलिए यह एक अच्छा मामला नहीं होगा .forEach(), लेकिन बहुत समय, जब कोई सरणी से शुरू होता है, forEach() एक अच्छी पसंद है, जैसे: var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; }); - JLRishe


पार्टी के लिए देर हो चुकी है, लेकिन मैं आज इस मुद्दे की खोज कर रहा था और देखा कि कई जवाब पूरी तरह से संबोधित नहीं करते हैं कि कैसे जावास्क्रिप्ट स्कॉप्स का व्यवहार करता है, जो अनिवार्य रूप से यह उबलता है।

तो जैसा कि कई अन्य लोगों ने उल्लेख किया है, समस्या यह है कि आंतरिक कार्य इसका संदर्भ दे रहा है i चर। तो हम प्रत्येक पुनरावृत्ति को एक नया स्थानीय चर क्यों नहीं बनाते हैं, और इसके बजाय आंतरिक फ़ंक्शन संदर्भ है?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

बस पहले की तरह, जहां प्रत्येक आंतरिक फ़ंक्शन को निर्दिष्ट अंतिम मान आउटपुट किया गया था i, अब प्रत्येक आंतरिक फ़ंक्शन केवल अंतिम मान को आउटपुट करता है ilocal। लेकिन प्रत्येक पुनरावृत्ति में यह स्वयं नहीं होना चाहिए ilocal?

बाहर निकलता है, यह मुद्दा है। प्रत्येक पुनरावृत्ति एक ही दायरे को साझा कर रहा है, इसलिए पहले के बाद हर पुनरावृत्ति सिर्फ ओवरराइटिंग है ilocal। से MDN:

महत्वपूर्ण: जावास्क्रिप्ट में ब्लॉक स्कोप नहीं है। ब्लॉक के साथ पेश किए गए वेरिएबल्स को फ़ंक्शन या स्क्रिप्ट में स्कॉप्ड किया जाता है, और उन्हें सेट करने के प्रभाव ब्लॉक से परे बने रहते हैं। दूसरे शब्दों में, ब्लॉक स्टेटमेंट्स एक दायरा पेश नहीं करते हैं। यद्यपि "स्टैंडअलोन" ब्लॉक वैध वाक्यविन्यास हैं, लेकिन आप जावास्क्रिप्ट में स्टैंडअलोन ब्लॉक का उपयोग नहीं करना चाहते हैं, क्योंकि वे ऐसा नहीं करते हैं जो आप सोचते हैं कि वे करते हैं, अगर आपको लगता है कि वे सी या जावा में ऐसे ब्लॉक की तरह कुछ करते हैं।

जोर के लिए दोहराया गया:

जावास्क्रिप्ट में ब्लॉक स्कोप नहीं है। ब्लॉक के साथ पेश किए गए वेरिएबल्स को फ़ंक्शन या स्क्रिप्ट में स्कॉप्ड किया जाता है

हम इसे जांचकर देख सकते हैं ilocal इससे पहले कि हम इसे प्रत्येक पुनरावृत्ति में घोषित करें:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

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

Closures

इसका यह भी अर्थ है कि आंतरिक कार्य बाहरी चर को "पकड़ते हैं" और उन्हें जीवित रखते हैं, भले ही बाहरी कार्य वापस आ जाए। इसका उपयोग करने के लिए, हम एक नया दायरा बनाने के लिए पूरी तरह से एक रैपर फ़ंक्शन बनाते हैं और कॉल करते हैं, घोषित करें ilocalनए दायरे में, और एक आंतरिक समारोह का उपयोग करता है जो उपयोग करता है ilocal (नीचे अधिक स्पष्टीकरण):

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

एक रैपर फ़ंक्शन के अंदर आंतरिक फ़ंक्शन बनाना आंतरिक कार्य को एक निजी वातावरण प्रदान करता है जो केवल "बंद" हो सकता है। इस प्रकार, हर बार हम रैपर फ़ंक्शन को कॉल करते हैं, हम इसे अपने स्वयं के अलग वातावरण के साथ एक नया आंतरिक कार्य बनाते हैं, यह सुनिश्चित करते हुए ilocal चर एक दूसरे को टक्कर और ओवरराइट नहीं करते हैं। कुछ मामूली अनुकूलन अंतिम जवाब देते हैं कि कई अन्य SO उपयोगकर्ताओं ने दिया:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

अद्यतन करें

ईएस 6 अब मुख्यधारा के साथ, अब हम नए का उपयोग कर सकते हैं let ब्लॉक-स्कोप्ड चर बनाने के लिए कीवर्ड:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

देखो अब कितना आसान है! अधिक जानकारी के लिए देखें यह जवाब, जो मेरी जानकारी के आधार पर आधारित है।


127
2018-04-10 09:57



मुझे पसंद है कि आपने आईआईएफई तरीके को कैसे समझाया। मैं उस की तलाश में था। धन्यवाद। - CapturedTree
जावास्क्रिप्ट में ब्लॉक स्कोपिंग के रूप में अब ऐसी चीज है let तथा const कीवर्ड। यदि यह उत्तर विस्तारित करने के लिए विस्तारित किया गया था, तो यह मेरी राय में अधिक वैश्विक रूप से उपयोगी होगा। - Tiny Giant
@TinyGiant निश्चित बात, मैंने कुछ जानकारी के बारे में जोड़ा let और एक और पूर्ण स्पष्टीकरण जुड़ा हुआ है - woojoo666
@ woojoo666 क्या आपका उत्तर दो वैकल्पिक यूआरएल को लूप में कॉल करने के लिए भी काम कर सकता है: i=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }? (getelementbyid के साथ window.open () को प्रतिस्थापित कर सकता है ......) - nutty about natty
@nuttyaboutnatty इस तरह के देर से जवाब के बारे में खेद है। ऐसा लगता है कि आपके उदाहरण में कोड पहले से ही काम नहीं करता है। आप उपयोग नहीं कर रहे हैं i आपके टाइमआउट फ़ंक्शंस में, इसलिए आपको बंद होने की आवश्यकता नहीं है - woojoo666


ES6 अब व्यापक रूप से समर्थित है, इस प्रश्न का सबसे अच्छा जवाब बदल गया है। ईएस 6 प्रदान करता है let तथा const इस सटीक परिस्थिति के लिए खोजशब्द। बंद होने के साथ घूमने के बजाय, हम बस उपयोग कर सकते हैं let इस तरह एक लूप स्कोप चर सेट करने के लिए:

var funcs = [];
for (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

val फिर उस ऑब्जेक्ट को इंगित करेगा जो लूप के उस विशेष मोड़ के लिए विशिष्ट है, और अतिरिक्त बंद नोटेशन के बिना सही मान वापस कर देगा। यह स्पष्ट रूप से इस समस्या को सरल बनाता है।

const के समान है let अतिरिक्त प्रतिबंध के साथ कि प्रारंभिक असाइनमेंट के बाद परिवर्तनीय नाम को नए संदर्भ में रीबाउंड नहीं किया जा सकता है।

ब्राउज़रों के नवीनतम संस्करणों को लक्षित करने वालों के लिए ब्राउज़र समर्थन अब यहां है। const/let वर्तमान में नवीनतम फ़ायरफ़ॉक्स, सफारी, एज और क्रोम में समर्थित हैं। यह नोड में भी समर्थित है, और आप इसे बेबेल जैसे निर्माण उपकरण का लाभ उठाकर कहीं भी उपयोग कर सकते हैं। आप यहां एक कामकाजी उदाहरण देख सकते हैं: http://jsfiddle.net/ben336/rbU4t/2/

यहां डॉक्स:

सावधान रहें, हालांकि, एज 14 समर्थन से पहले IE9-IE11 और एज let लेकिन उपरोक्त गलत प्राप्त करें (वे एक नया नहीं बनाते हैं i हर बार, तो ऊपर दिए गए सभी कार्य 3 लॉग करेंगे जैसे कि अगर हम इस्तेमाल करते हैं तो वे करेंगे var)। एज 14 आखिरकार यह सही हो जाता है।


121
2018-05-21 03:04



दुर्भाग्यवश, 'चलो' अभी भी पूरी तरह से समर्थित नहीं है, खासकर मोबाइल में। developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - MattC
जून 1616 तक, चलो आईओएस सफारी, ओपेरा मिनी और सफारी 9 को छोड़कर सभी प्रमुख ब्राउज़र संस्करणों में समर्थित है। सदाबहार ब्राउज़र इसका समर्थन करते हैं। उच्च जटिलता मोड स्विच किए बिना अपेक्षित व्यवहार को रखने के लिए बेबेल इसे सही तरीके से पारदर्शी कर देगा। - Dan Pantry
@DanPantry हाँ अद्यतन के लिए समय के बारे में :) कॉन्स, दस्तावेज़ लिंक और बेहतर संगतता जानकारी का उल्लेख जोड़ने सहित, वर्तमान स्थिति की स्थिति को बेहतर ढंग से प्रतिबिंबित करने के लिए अपडेट किया गया। - Ben McCormick
ऐसा नहीं है कि हम अपने कोड को पारदर्शी करने के लिए बेबेल का उपयोग क्यों करते हैं ताकि ब्राउज़र जो ES6 / 7 का समर्थन नहीं करते हैं, समझ सकते हैं कि क्या हो रहा है? - pixel 67


यह कहने का एक और तरीका यह है कि i फ़ंक्शन को निष्पादित करने के समय आपके फ़ंक्शन में फ़ंक्शन निष्पादित करने के समय बाध्य है।

जब आप बंद करते हैं, i बाहरी दायरे में परिभाषित चर के संदर्भ में है, इसकी एक प्रति नहीं, क्योंकि जब आप बंद कर देते थे। निष्पादन के समय इसका मूल्यांकन किया जाएगा।

अन्य अधिकांश उत्तर एक और चर बनाकर काम करने के तरीके प्रदान करते हैं जो आपके लिए मूल्य नहीं बदलेगा।

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


77
2018-04-15 06:48





आपको समझने की आवश्यकता है कि जावास्क्रिप्ट में चर का दायरा फ़ंक्शन पर आधारित है। सी # कहने से यह एक महत्वपूर्ण अंतर है जहां आपके पास ब्लॉक स्कोप है, और सिर्फ वैरिएबल को कॉपी करने के लिए एक के अंदर कॉपी करना होगा।

एपैकर के उत्तर जैसे फ़ंक्शन को वापस करने का मूल्यांकन करने वाले फ़ंक्शन में इसे लपेटने से चाल चलती है, क्योंकि चर के पास फ़ंक्शन स्कोप होता है।

Var के बजाय एक लेट कीवर्ड भी है, जो ब्लॉक स्कोप नियम का उपयोग करने की अनुमति देगा। उस स्थिति में एक चर को परिभाषित करने के लिए चाल चलती है। उस ने कहा, चलो कीवर्ड संगतता के कारण व्यावहारिक समाधान नहीं है।

var funcs = {};
for (var i = 0; i < 3; i++) {
    let index = i;          //add this
    funcs[i] = function() {            
        console.log("My value: " + index); //change to the copy
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        
}

61
2018-04-15 06:25



@nickf कौन सा ब्राउज़र? जैसा कि मैंने कहा, इसमें संगतता समस्याएं हैं, जिसका अर्थ है कि मेरा मतलब गंभीर संगतता समस्या है, जैसे मुझे नहीं लगता कि चलिए आईई में समर्थित हैं। - eglasius
@nickf हाँ, इस संदर्भ की जांच करें: developer.mozilla.org/En/New_in_JavaScript_1.7 ... चलो परिभाषा अनुभाग की जांच करें, एक लूप के अंदर एक ऑनक्लिक उदाहरण है - eglasius
@nickf hmm, वास्तव में आपको संस्करण को स्पष्ट रूप से निर्दिष्ट करना होगा: <script type = "application / javascript; version = 1.7" /> ... मैंने वास्तव में आईई प्रतिबंध के कारण कहीं भी इसका उपयोग नहीं किया है, यह सिर्फ नहीं है व्यावहारिक :( - eglasius
यह भी देखें वर्तमान में कौन से ब्राउज़र जावास्क्रिप्ट के 'चलो' कीवर्ड का समर्थन करते हैं? - rds
तब उपयोग न करें - regisbsb


तकनीक पर एक और भिन्नता है, जो Bjorn's (apphacker) के समान है, जो आपको पैरामीटर के रूप में इसे पास करने के बजाय फ़ंक्शन के अंदर चर मान को असाइन करने देता है, जो कभी-कभी स्पष्ट हो सकता है:

for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

ध्यान दें कि आप जो भी तकनीक उपयोग करते हैं, वह index परिवर्तनीय स्थिर चर का एक प्रकार बन जाता है, जो आंतरिक कार्य की लौटाई गई प्रतिलिपि से बंधे होते हैं। यानी, इसके मूल्य में परिवर्तन कॉल के बीच संरक्षित हैं। यह बहुत आसान हो सकता है।


49
2017-08-07 08:45



धन्यवाद और आपका समाधान काम करता है। लेकिन मैं पूछना चाहता हूं कि यह क्यों काम करता है, लेकिन स्वैपिंग var रेखा और return लाइन काम नहीं करेगा? धन्यवाद! - midnite
@ मिडनाइट अगर आप बदल गए हैं var तथा return तो परिवर्तक को आंतरिक कार्य वापस करने से पहले असाइन नहीं किया जाएगा। - Boann