2013-05-10 7 views
32

ईसीएमएस्क्रिप्ट 6 के let में कीवर्ड को सिरदर्द के बिना ब्लॉक स्कोप प्रदान करना है। क्या कुछ बता सकते हैं कि फ़ंक्शन में i से नीचे दिए गए कोड में वर्तमान पुनरावृत्ति से मूल्य के बजाय लूप से अंतिम मान (जैसे var) के साथ हल किया गया है?कीवर्ड को लूप

"use strict"; 
var things = {}; 
for (let i = 0; i < 3; i++) { 
    things["fun" + i] = function() { 
     console.log(i); 
    }; 
} 

things["fun0"](); // prints 3 
things["fun1"](); // prints 3 
things["fun2"](); // prints 3 
MDN for पाश की तरह में let का उपयोग कर पाश के शरीर के दायरे में चर के लिए बाध्य करना चाहिए के अनुसार

। जब मैं ब्लॉक के अंदर अस्थायी चर का उपयोग करता हूं तो चीजें काम करती हैं क्योंकि मैं उनसे अपेक्षा करता हूं। यह जरूरी क्यों है?

"use strict"; 
var things = {}; 
for (let i = 0; i < 3; i++) { 
    let index = i; 
    things["fun" + i] = function() { 
     console.log(index); 
    }; 
} 

things["fun0"](); // prints 0 
things["fun1"](); // prints 1 
things["fun2"](); // prints 2 

मैं Traceur और node --harmony साथ स्क्रिप्ट का परीक्षण किया।

+0

टीएल; डीआर: पहला कोड स्निपेट पर्यावरण के जावास्क्रिप्ट कार्यान्वयन में एक बग प्रदर्शित करता है। यही है, सही व्यवहार 3, 3 और 3 के बजाय 0, 1 और 2 आउटपुट करना है। जब आप कोड चलाते हैं तो आधुनिक ब्राउज़र सही तरीके से काम करते हैं और 0, 1 और 2 आउटपुट करते हैं। – Utku

+0

स्पष्ट रूप से यहां तीन अलग-अलग स्कॉप्स हैं: 'x = 5 दें; के लिए (चलो एक्स = 0; एक्स <10; एक्स ++) {चलो x = 3; console.log (x); } ' – joeytwiddle

उत्तर

35

स्क्विंट का उत्तर अब अद्यतित नहीं है। ECMA 6 specification में, निर्दिष्ट व्यवहार है कि

for(let i;;){} 

i में पाश के हर यात्रा के लिए एक नया बाध्यकारी हो जाता है।

इसका मतलब है कि प्रत्येक बंद एक अलग i उदाहरण कैप्चर करता है। तो 012 का नतीजा अब तक सही परिणाम है। जब आप इसे क्रोम v47 + में चलाते हैं, तो आपको सही परिणाम मिल जाता है। जब आप इसे IE11 और Edge में चलाते हैं, तो वर्तमान में गलत परिणाम (333) उत्पन्न होता प्रतीत होता है।

इस बग/फीचर के बारे में अधिक जानकारी this page में लिंक में पाई जा सकती है;

जब से let अभिव्यक्ति का उपयोग किया जाता है, तो प्रत्येक पुनरावृत्ति पिछले दायरे तक एक नया अक्षीय दायरा बनाता है। let अभिव्यक्ति का उपयोग करने के लिए इसका प्रदर्शन प्रभाव पड़ता है, जो here की सूचना दी गई है।

+7

विचित्र रूप से, हालांकि यह एक अलग उदाहरण है, यदि लूप के प्रत्येक पुनरावृत्ति में' i' है, तो लूप के भीतर 'i' का कोई भी संशोधन अभी भी लूप की पुनरावृत्ति गणना को प्रभावित करता है। यह एक अजीब जानवर है, आधे अलग परिवर्तनीय, मूल के आधे संदर्भ। प्रत्येक नए पुनरावृत्ति की शुरुआत में – jfriend00

+0

@ jfriend00, एक नया शब्दावली का दायरा स्थापित किया गया है, और पिछले क्षेत्र में "i" का मान कॉपी किया गया है। – neuron

+1

हां, मुझे पता है कि। लेकिन, यह एक शुद्ध प्रति नहीं है क्योंकि लूप के दौरान इसे संशोधित करना अभी भी लूप वैरिएबल को प्रभावित करता है। तो, यह प्रत्येक लूप निष्पादन के अंत में कुछ होना चाहिए, इसका मूल्य लूप काउंटर पर वापस कॉपी किया गया है। – jfriend00

6

मैं Babel के माध्यम से इस कोड को पारित कर दिया तो हम परिचित ES5 के मामले में व्यवहार को समझने कर सकते हैं:

var _loop = function _loop(_i) { 
    _i++; 
    things["fun" + _i] = function() { 
     console.log(_i); 
    }; 
    _i--; 
    i = _i; 
}; 

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

हम देख सकते हैं कि दो चर:

for (let i = 0; i < 3; i++) { 
    i++; 
    things["fun" + i] = function() { 
     console.log(i); 
    }; 
    i--; 
} 

यहाँ ES5 को transpiled कोड है उपयोग किया जाता है।

  • बाहरी गुंजाइश i में चर के रूप में हम पुनरावृति बदल जाता है।

  • आंतरिक दायरे में _i प्रत्येक पुनरावृत्ति के लिए एक अद्वितीय चर है। अंत में _i के तीन अलग-अलग उदाहरण होंगे।

    प्रत्येक कॉलबैक फ़ंक्शन इसके संबंधित _i देख सकता है, और अगर यह चाहता था कि वह _i एस के अन्य क्षेत्रों में स्वतंत्र रूप से इसे भी कुशलतापूर्वक उपयोग कर सके।

    (आप पुष्टि कर सकते हैं वहाँ कॉलबैक अंदर console.log(i++) करके तीन अलग अलग _i रों रहे हैं। पहले के एक कॉलबैक में _i बदलने बाद में कॉलबैक से उत्पादन प्रभावित नहीं करता।)

प्रत्येक यात्रा के अंत में, _i का मूल्य i में बनाई जाए। इसलिए पुनरावृत्ति के दौरान अद्वितीय आंतरिक चर बदलना बाहरी पुनरावृत्त चर को प्रभावित करेगा।

यह देखना अच्छा है कि ईएस 6 ने डब्ल्यूटीएफजेएस की दीर्घकालिक परंपरा जारी रखी है।

+2

+1 जिसमें बेबेल अनुवाद शामिल है, जो वास्तव में देखने के लिए उपयोगी है, धन्यवाद! हालांकि, सिर्फ इसलिए कि बेबेल को पुराने गैर-ईएस 6 अनुरूप ब्राउज़र में काम करने के लिए कीवर्ड को अनुवाद करने के लिए wtf हैक्स का उपयोग करना है, इसका मतलब यह नहीं है कि ईएस 6 आधुनिक ब्राउज़र कार्यान्वयन में है। –

+1

चार्ली के साथ सहमत हैं। लेकिन इसके अलावा, डब्ल्यूटीएफजेएस खड़ा है। आप यह क्यों मानना ​​चाहेंगे कि लूप काउंटर लूप के माध्यम से हर बार एक अलग चर है? मैं यह मानना ​​चाहता हूं कि यह वही है (इस मामले में एलईटी स्थानीय लूप के लिए इंगित करेगा)। मैं इसे सबसे बड़ी परिमाण का एक मस्तिष्क भाग्य मानता हूं। कोड बनाने के लिए कोड (लेकिन बाहरी दायरे से अलग) अब उपयोग करने के लिए एक नया चर बनाने के लिए एक लाइन जोड़ने से कहीं अधिक कठिन है। –

0

आईएमएचओ - प्रोग्रामर जिन्होंने पहली बार इस एलईटी को लागू किया (आपके प्रारंभिक संस्करण के परिणामों का उत्पादन) ने इसे स्वच्छता के संबंध में सही ढंग से किया; हो सकता है कि वे उस कार्यान्वयन के दौरान spec पर glanced नहीं देखा हो सकता है।

यह अधिक समझ में आता है कि एक चर का उपयोग किया जा रहा है, लेकिन लूप के लिए scoped। विशेष रूप से जब किसी को लूप के भीतर स्थितियों के आधार पर उस चर को बदलने के लिए स्वतंत्र महसूस करना चाहिए।

लेकिन प्रतीक्षा करें - आप लूप चर बदल सकते हैं। WTFJS !! हालांकि, अगर आप इसे अपने आंतरिक दायरे में बदलने का प्रयास करते हैं, तो यह अब काम नहीं करेगा क्योंकि यह एक नया चर है।

मैं मैं मैं क्या चाहते हैं (एकल वैरिएबल उस के लिए करने के लिए स्थानीय है) प्राप्त करने के लिए क्या करना है पसंद नहीं है:

{ 
    let x = 0; 
    for (; x < length; x++) 
    { 
     things["fun" + x] = function() { 
      console.log(x); 
     }; 
    } 
} 

कहाँ के रूप में अधिक सहज ज्ञान युक्त संशोधित करने के लिए (यदि काल्पनिक) संस्करण यात्रा प्रति एक नया वेरिएबल को संभालने के लिए:

for (let x = 0; x < length; x++) 
{ 
    let y = x; 
    things["fun" + y] = function() { 
     console.log(y); 
    }; 
} 

यह एकदम साफ है कि क्या y चर के साथ मेरा इरादा .. है या किया गया है, तो विवेक ब्रह्मांड फैसला सुनाया जाएगा।

तो आपका पहला उदाहरण अब एफएफ में काम करता है; यह 0, 1, 2 उत्पन्न करता है। आपको समस्या को ठीक करने के लिए कहा जाता है। मैं इस मुद्दे को डब्ल्यूटीएफजेएस कहते हैं।

ps। डब्ल्यूटीएफजेएस का मेरा संदर्भ ऊपर जॉयटविल्ड से है; यह एक मेम जैसा लगता है जो मुझे आज से पहले जाना चाहिए था, लेकिन आज इसे सीखने का एक अच्छा समय था।

संबंधित मुद्दे