ES6 में लेट या कास्ट के साथ घोषित चर नहीं हैं?


266

मैं थोड़ी देर के लिए ES6 के साथ खेल रहा हूं और मैंने देखा कि जब तक घोषित किए गए चर varउम्मीद के मुताबिक होते हैं ...

console.log(typeof name); // undefined
var name = "John";

... चर के साथ घोषित letया constलगता है कि उत्थापन के साथ कुछ समस्याएं हैं:

console.log(typeof name); // ReferenceError
let name = "John";

तथा

console.log(typeof name); // ReferenceError
const name = "John";

क्या इसका मतलब यह है कि चरों को घोषित किया गया है letया constफहराया नहीं गया है? यहाँ वास्तव में क्या हो रहा है? वहाँ के बीच कोई अंतर है letऔर constइस मामले में?

जवाबों:


346

@thefourtheye यह कहने में सही है कि इन चरों को घोषित किए जाने से पहले एक्सेस नहीं किया जा सकता है । हालाँकि, यह उससे थोड़ा अधिक जटिल है।

क्या चर को घोषित किया गया है letया constनहीं फहराया गया है? यहाँ वास्तव में क्या हो रहा है?

सभी घोषणाओं ( var, let, const, function, function*, class) "फहराया" कर रहे हैं जावास्क्रिप्ट में। इसका मतलब यह है कि यदि किसी नाम को एक दायरे में घोषित किया जाता है, तो उस दायरे में पहचानकर्ता हमेशा उस विशेष चर का संदर्भ देगा:

x = "global";
// function scope:
(function() {
    x; // not "global"

    var/let/… x;
}());
// block scope (not for `var`s):
{
    x; // not "global"

    let/const/… x;
}

यह फ़ंक्शन और ब्लॉक स्कोप 1 के लिए सच है ।

var/ function/ function*घोषणाओं और let/ const/ classघोषणाओं के बीच का अंतर आरंभीकरण है
पूर्व को undefined(जनरेटर) फ़ंक्शन के साथ आरंभीकृत किया जाता है जब दायरा के शीर्ष पर बाइंडिंग बनाई जाती है। Lexically घोषित चर तथापि रहने uninitialised । इसका मतलब है कि ReferenceErrorजब आप इसे एक्सेस करने की कोशिश करते हैं तो एक अपवाद फेंक दिया जाता है। यह केवल तब ही आरंभ हो जाएगा जब let/ const/ classकथन का मूल्यांकन किया जाता है, इससे पहले कि सब कुछ (ऊपर) जिसे अस्थायी मृत क्षेत्र कहा जाता है ।

x = y = "global";
(function() {
    x; // undefined
    y; // Reference error: y is not defined

    var x = "local";
    let y = "local";
}());

ध्यान दें कि एक let y;स्टेटमेंट इस undefinedतरह के वेरिएबल को इनिशियलाइज़ करता let y = undefined;है।

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

वहाँ के बीच कोई अंतर है letऔर constइस मामले में?

नहीं, वे वही काम करते हैं जहां तक ​​उत्थापन माना जाता है। उनके बीच एकमात्र अंतर यह है कि एक constचींटी होनी चाहिए और केवल घोषणा के प्रारंभिक भाग में सौंपी जा सकती है (जैसे const one = 1;, दोनों const one;और बाद के पुनर्मूल्यांकन one = 2अमान्य हैं)।

1: varघोषणाएं अभी भी केवल फ़ंक्शन स्तर पर काम कर रही हैं, निश्चित रूप से


16
मुझे लगता है कि सभी घोषणाओं कोlet foo = () => bar; let bar = 'bar'; foo(); दर्शाने जैसा कुछ बेहतर प्रभाव है, क्योंकि यह अस्थायी मृत क्षेत्र के कारण स्पष्ट नहीं है।
एस्टस फ्लास्क

1
मैं लेट (यानी एक बंद) से पहले घोषित एक फ़ंक्शन में एक लेट डेफिनेशन के बारे में पूछने वाला था। मुझे लगता है कि यह सवाल का जवाब देता है, यह कानूनी है, लेकिन यदि कोई त्रुटि है तो फ़ंक्शन को लेट स्टेटमेंट से पहले लागू किया जाएगा, और यदि बाद में फ़ंक्शन को लागू किया जाता है, तो यह ठीक होगा। अगर यह सच हो तो जवाब में जोड़ा जा सकता है?
माइक लिपर्ट

2
@ माइकलाइपर्ट हाँ, यह सही है। प्रारंभ होने से पहले आपको चर को एक्सेस करने वाले फ़ंक्शन को कॉल नहीं करना चाहिए। यह परिदृश्य प्रत्येक फहराए गए फ़ंक्शन घोषणा के साथ होता है, उदाहरण के लिए।
बर्गी

1
constजैसा बनाने का निर्णय letएक डिजाइन दोष है। एक दायरे के भीतर, constइसे फहराया जाना चाहिए और जब यह एक्सेस किया जाता है तो समय-समय पर प्रारंभिक। वास्तव में, उनके पास एक const, एक letऔर एक और कीवर्ड होना चाहिए जो एक चर बनाता है जो "आसानी से" की तरह काम करता है let
पचेरियर

1
" पूर्व को अपरिभाषित के साथ आरंभ किया जाता है ..." var घोषणाओं के लिए ठीक हो सकता है, लेकिन फ़ंक्शन घोषणाओं के लिए उपयुक्त नहीं लगता है, जिन्हें निष्पादन शुरू होने से पहले एक मान सौंपा जाता है।
रोबग

87

ECMAScript 6 (ECMAScript 2015) विनिर्देशन, letऔर constघोषणाएँ अनुभाग का हवाला देते हुए ,

वैरिएबल तब बनाए जाते हैं, जब उनके लेक्सिकल एनवायरनमेंट को त्वरित किया जाता है लेकिन किसी भी तरह से तब तक एक्सेस नहीं किया जा सकता है जब तक कि वेरिएबल की लेक्सिकलबाइंडिंग का मूल्यांकन नहीं किया जाता है

इसलिए, आपके प्रश्न का उत्तर देने के लिए, हां, letऔर constलहराएं लेकिन आप रनटाइम पर मूल्यांकन किए जाने से पहले वास्तविक घोषणा का उपयोग नहीं कर सकते।


22

ES6उन Letचरों का परिचय देता है जो साथ आते हैं block level scoping। जब तक ES5हमारे पास नहीं था block level scoping, इसलिए एक खंड के अंदर घोषित होने वाले चर हमेशा hoistedस्तर पर कार्य करने के लिए होते हैं ।

मूल रूप से Scopeसंदर्भित करता है कि आपके कार्यक्रम में आपके चर कहां दिखाई दे रहे हैं, जो यह निर्धारित करता है कि आपके द्वारा घोषित चर का उपयोग करने की अनुमति कहां है। में ES5हमारे पास global scope,function scope and try/catch scope, के साथ ES6हम भी ब्लॉक स्तर scoping Let का उपयोग करके मिलता है।

  • जब आप varकीवर्ड के साथ एक चर को परिभाषित करते हैं , तो यह उस क्षण से पूरे फ़ंक्शन को ज्ञात होता है जो इसे परिभाषित करता है।
  • जब आप किसी चर को उस letकथन से परिभाषित करते हैं, जिसे वह केवल उस खंड में जाना जाता है जिसे वह परिभाषित करता है।

     function doSomething(arr){
         //i is known here but undefined
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(var i=0; i<arr.length; i++){
             //i is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(let j=0; j<arr.length; j++){
             //j is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
     }
    
     doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);

यदि आप कोड चलाते हैं, तो आप देख सकते हैं कि चर jकेवल loopपहले और बाद में ही जाना जाता है । फिर भी, हमारे वेरिएबल iको entire functionउस समय से जाना जाता है जब इसे आगे परिभाषित किया जाता है।

एक और बढ़िया फायदा यह है कि इसे एक नए संदर्भ का माहौल बनाने के साथ-साथ एक पुराने संदर्भ को रखने के बजाय नए मूल्य में बांधता है।

for(var i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

for(let i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

पहला forलूप हमेशा अंतिम मान को प्रिंट करता है , इसके साथ letएक नया स्कोप बनता है और हमें प्रिंट करने वाले नए मानों को बांधता है 1, 2, 3, 4, 5

करने के लिए आ रहा है constants, यह मूल रूप से काम करते हैं let, फर्क सिर्फ इतना है कि उनके मूल्य को बदला नहीं जा सकता है। स्थिरांक में उत्परिवर्तन की अनुमति है लेकिन पुनर्मूल्यांकन की अनुमति नहीं है।

const foo = {};
foo.bar = 42;
console.log(foo.bar); //works

const name = []
name.push("Vinoth");
console.log(name); //works

const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.

console.log(age);

यदि एक स्थिरांक एक को संदर्भित करता है object, तो यह हमेशा संदर्भित होगा objectलेकिन objectस्वयं को बदला जा सकता है (यदि यह परिवर्तनशील है)। यदि आपको कोई अपरिवर्तनीय पसंद है object, तो आप उपयोग कर सकते हैंObject.freeze([])


5

से MDN वेब डॉक्स:

ECMAScript 2015 में, letऔर constफहराए गए लेकिन आरंभिक नहीं। चर घोषित होने से पहले ब्लॉक में चर को संदर्भित करना ReferenceErrorक्योंकि चर घोषणा शुरू होने तक ब्लॉक की शुरुआत से "अस्थायी मृत क्षेत्र" में होता है।

console.log(x); // ReferenceError
let x = 3;

0

es6 में जब हम let या const का उपयोग करते हैं तो हमें उन्हें उपयोग करने से पहले वैरिएबल घोषित करना होगा। जैसे। 1 -

// this will work
u = 10;
var u;

// this will give an error 
k = 10;
let k;  // ReferenceError: Cannot access 'k' before initialization.

जैसे। 2-

// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.