javascript जावास्क्रिप्ट में एक चर घोषित करने के लिए "let" और "var" का उपयोग करने के बीच क्या अंतर है?




scope ecmascript-6 (22)

let और var बीच क्या अंतर है?

  • एक var कथन का उपयोग करके परिभाषित एक चर को फ़ंक्शन की शुरुआत से परिभाषित किया गया फ़ंक्शन में जाना जाता है। (*)
  • एक let स्टेटमेंट का उपयोग करके परिभाषित एक चर केवल उस ब्लॉक में जाना जाता है जिसे परिभाषित किया गया है, जिस क्षण से इसे परिभाषित किया गया है। (**)

अंतर को समझने के लिए, निम्न कोड पर विचार करें:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

यहां, हम देख सकते हैं कि हमारे चर j को केवल लूप के लिए पहले जाना जाता है, लेकिन पहले और बाद में नहीं। फिर भी, हमारे चर i पूरे समारोह में जाना जाता है।

साथ ही, मान लें कि ब्लॉक स्कॉप्ड वैरिएबल घोषित होने से पहले ज्ञात नहीं हैं क्योंकि वे फट नहीं गए हैं। आपको उसी ब्लॉक के भीतर एक ही ब्लॉक स्कोप्ड वैरिएबल को फिर से चलाने की अनुमति नहीं है। यह ब्लॉक स्कोप्ड वेरिएबल्स को वैश्विक स्तर पर या कार्यात्मक रूप से स्कॉप्ड चर के मुकाबले कम त्रुटि प्रवण बनाता है, जो फहराया जाता है और जो कई घोषणाओं के मामले में कोई त्रुटि उत्पन्न नहीं करता है।

क्या आज उपयोग करना सुरक्षित है?

कुछ लोग तर्क देंगे कि भविष्य में हम केवल बयानों का उपयोग करेंगे और वे कथन कथन अप्रचलित हो जाएंगे। जावास्क्रिप्ट गुरु काइल सिम्पसन ने एक बहुत ही विस्तृत लेख लिखा कि ऐसा क्यों नहीं है

आज, हालांकि, यह निश्चित रूप से मामला नहीं है। वास्तव में, हमें वास्तव में खुद से पूछना चाहिए कि क्या यह बयान कथन का उपयोग सुरक्षित है या नहीं। उस प्रश्न का उत्तर आपके पर्यावरण पर निर्भर करता है:

  • यदि आप सर्वर-साइड जावास्क्रिप्ट कोड ( Node.js ) लिख रहे हैं, तो आप सुरक्षित रूप से let स्टेटमेंट का उपयोग कर सकते हैं।

  • यदि आप क्लाइंट-साइड जावास्क्रिप्ट कोड लिख रहे हैं और एक ट्रांस्सेलर (जैसे ट्रेसेर) का उपयोग करते हैं, तो आप सुरक्षित रूप से let स्टेटमेंट का उपयोग कर सकते हैं, हालांकि आपका कोड प्रदर्शन के संबंध में इष्टतम लेकिन कुछ भी होने की संभावना है।

  • यदि आप क्लाइंट-साइड जावास्क्रिप्ट कोड लिख रहे हैं और एक ट्रांसलेटर का उपयोग नहीं करते हैं, तो आपको ब्राउज़र समर्थन पर विचार करने की आवश्यकता है।

आज, 8 जून 2018, अभी भी कुछ ब्राउज़र हैं जो समर्थन नहीं करते let !

ब्राउज़र समर्थन का ट्रैक कैसे रखें

इस उत्तर को पढ़ने के समय कौन से ब्राउज़र let स्टेटमेंट का समर्थन करते हैं, इसके बारे में एक अद्यतित अवलोकन के लिए, देखें कि Can I Use पृष्ठ का Can I Use

(*) वैश्विक स्तर पर और कार्यात्मक रूप से स्कॉप्ड चर प्रारंभ किए जा सकते हैं और घोषित किए जाने से पहले उपयोग किए जा सकते हैं क्योंकि जावास्क्रिप्ट चर को hoisted इसका मतलब यह है कि घोषणाएं हमेशा दायरे के शीर्ष पर बहुत अधिक होती हैं।

(**) ब्लॉक स्कॉप्ड वेरिएबल नहीं फंस गए हैं

ईसीएमएस्क्रिप्ट 6 ने let स्टेटमेंट पेश किया । मैंने इसे "स्थानीय" चर के रूप में वर्णित सुना है, लेकिन मुझे अभी भी यह सुनिश्चित नहीं है कि यह विभिन्न कीवर्ड से अलग तरीके से कैसे व्यवहार करता है।

क्या अंतर हैं? var पर इस्तेमाल कब किया जाना चाहिए?


चलो es6 का एक हिस्सा है। ये कार्य आसान तरीके से अंतर को समझाएंगे।

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

let दिलचस्प है, क्योंकि यह हमें ऐसा कुछ करने की अनुमति देता है:

(() => {
    var count = 0;

    for (let i = 0; i < 2; ++i) {
        for (let i = 0; i < 2; ++i) {
            for (let i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

[0, 7] गिनती के परिणाम।

जहाँ तक

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

केवल मायने रखता है [0, 1]।


अंतर गुंजाइश है। var को निकटतम फ़ंक्शन ब्लॉक पर स्कॉप्ड किया गया है और let निकटतम संलग्न ब्लॉक पर स्कॉप्ड किया गया है, जो फ़ंक्शन ब्लॉक से छोटा हो सकता है। यदि किसी भी ब्लॉक के बाहर दोनों ग्लोबल हैं।

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

Demo :

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

ग्लोबल:

फ़ंक्शन ब्लॉक के बाहर इस तरह उपयोग किए जाने पर वे बहुत समान होते हैं।

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

हालांकि, let साथ परिभाषित वैश्विक चर को वैश्विक window ऑब्जेक्ट पर गुणों के रूप में जोड़ा नहीं जाएगा जैसे कि var साथ परिभाषित किया गया है।

console.log(window.me); // undefined
console.log(window.i); // 'able'

समारोह:

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

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

ब्लॉक:

यहां अंतर है। let केवल for() लूप में दिखाई देता है और var पूरे फ़ंक्शन के लिए दृश्यमान होता है।

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

पुन: घोषणा:

सख्त मोड मानते हुए, var आपको उसी वैरिएबल में एक ही चर को फिर से घोषित करने देगा। दूसरी ओर, let नहीं करेंगे:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.

पहले जावास्क्रिप्ट में केवल दो स्कोप थे, यानी कार्यात्मक और वैश्विक। 'के साथ let' कीवर्ड जावास्क्रिप्ट अब शुरू की है block-levelचर।

'लेट' कीवर्ड की पूरी समझ रखने के लिए, ES6: जावास्क्रिप्ट में परिवर्तनीय घोषित करने के लिए कीवर्ड 'चलो' मदद करेगा।


मुख्य अंतर गुंजाइश अंतर है, जबकि इसे केवल उस दायरे के अंदर ही उपलब्ध किया जा सकता है, जैसे कि लूप के लिए, उदाहरण के लिए लूप के बाहर var को एक्सेस किया जा सकता है। एमडीएन में दस्तावेज से (एमडीएन से भी उदाहरण):

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

घोषित वैरिएबल को उनके दायरे को ब्लॉक के रूप में परिभाषित किया गया है, साथ ही किसी भी निहित उप-ब्लॉक में। इस तरह, var var की तरह काम करता है। मुख्य अंतर यह है कि एक var चर का दायरा पूरे संलग्न कार्य है:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

कार्यक्रमों और कार्यों के शीर्ष स्तर पर, var के विपरीत, वैश्विक वस्तु पर कोई संपत्ति नहीं बनाते हैं। उदाहरण के लिए:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

जब किसी ब्लॉक के अंदर उपयोग किया जाता है, तो उस ब्लॉक पर चर के दायरे को सीमित करने दें। Var के बीच का अंतर नोट करें जिसका दायरा उस समारोह के अंदर है जहां इसे घोषित किया गया है।

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

इसके अलावा यह ईसीएमए 6 फीचर को भी न भूलें, इसलिए यह अभी तक पूरी तरह से समर्थित नहीं है, इसलिए बैबेल इत्यादि का उपयोग करके ईसीएमए 5 पर इसे हमेशा बेहतर बना दिया जाता है ... बेबेल वेबसाइट पर जाने के बारे में अधिक जानकारी के लिए


  • परिवर्तनीय नहीं होस्टिंग

    let उस ब्लॉक के पूरे दायरे में नहीं उठेगा जो इसके विपरीत दिखाई देता है। इसके विपरीत, var नीचे के रूप में var सकता है।

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }
    

    असल में, प्रति @ बर्गि, दोनों var और चले गए हैं

  • कचरा इकठा करना

    let ब्लॉक का दायरा उपयोगी है जो स्मृति को पुनः प्राप्त करने के लिए बंद करने और कचरा संग्रह से संबंधित है। विचार करें,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    

    click हैंडलर कॉलबैक को hugeData वैरिएबल की आवश्यकता नहीं है। सैद्धांतिक रूप से, process(..) बाद, विशाल डेटा संरचना विशाल डेटा कचरा एकत्र किया जा सकता है। हालांकि, यह संभव है कि कुछ जेएस इंजन को अभी भी इस विशाल संरचना को रखना होगा, क्योंकि click फ़ंक्शन पूरे दायरे पर बंद हो गया है।

    हालांकि, ब्लॉक स्कोप इस विशाल डेटा संरचना को कचरे में एकत्र कर सकता है।

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    
  • लूप let

    लूप में लूप के प्रत्येक पुनरावृत्ति के लिए इसे फिर से बांध सकते हैं, यह सुनिश्चित करना कि पिछले लूप पुनरावृत्ति के अंत से मूल्य को फिर से असाइन करना सुनिश्चित करें। विचार करें,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    हालांकि, var साथ var को प्रतिस्थापित करें

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    क्योंकि ए के लिए उन नामों के साथ एक नया व्याख्यात्मक वातावरण बनाने let ) प्रारंभिक अभिव्यक्ति बी) प्रत्येक पुनरावृत्ति (वृद्धि वृद्धि अभिव्यक्ति का मूल्यांकन करने के लिए previosly), अधिक जानकारी here ।


var वैश्विक दायरा (उछाल-सक्षम) चर है।

letऔर constब्लॉक गुंजाइश है।

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined


स्वीकृत उत्तर में एक बिंदु गुम है:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined

एमडीएन में इस लिंक को देखें

let x = 1;

if (x === 1) {
let x = 2;

console.log(x);
// expected output: 2
}

console.log(x);
// expected output: 1

अब मुझे लगता है कि कथन के ब्लॉक में चर के बेहतर स्कोपिंग का उपयोग कर रहा है let:

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

मुझे लगता है कि लोग यहां उपयोग करने शुरू कर देंगे ताकि वे जावास्क्रिप्ट में अन्य भाषाओं, जावा, सी # इत्यादि जैसे समान स्कोपिंग कर सकें।

जावास्क्रिप्ट में स्कॉपिंग के बारे में स्पष्ट समझ वाले लोग पहले गलती करने के लिए इस्तेमाल करते थे।

Hoisting का उपयोग कर समर्थित नहीं है let

जावास्क्रिप्ट में मौजूद इस दृष्टिकोण त्रुटियों को हटा दिया जा रहा है।

गहराई में ES6 का संदर्भ लें : इसे समझने के लिए चलो और समझें।


बंद करने के साथ समस्याओं से बचने के लिए भी इस्तेमाल किया जा सकता है। यह नीचे दिए गए उदाहरणों में दिखाए गए पुराने संदर्भ को रखने के बजाय ताजा मूल्य बांधता है।

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

उपरोक्त कोड क्लासिक जावास्क्रिप्ट बंद करने की समस्या का प्रदर्शन करता है। i वैरिएबल को संदर्भ i के वास्तविक मूल्य की बजाय क्लिक हैंडलर क्लोजर में संग्रहीत किया जा रहा है।

प्रत्येक एकल क्लिक हैंडलर एक ही ऑब्जेक्ट को संदर्भित करेगा क्योंकि केवल एक काउंटर ऑब्जेक्ट है जिसमें 6 है, इसलिए आपको प्रत्येक क्लिक पर छः मिलते हैं।

सामान्य कामकाज इसे किसी अज्ञात फ़ंक्शन में लपेटना है और i तर्क के रूप में पास करना है। नीचे दिए गए कोड में दिखाए गए अनुसार बदले में बदले में ऐसे मुद्दों को भी टाला जा सकता है।

DEMO (क्रोम और फ़ायरफ़ॉक्स में परीक्षण 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

जैसा कि ऊपर उल्लेख किया गया है:

अंतर गुंजाइश है। varनिकटतम के दायरे वाला समारोह ब्लॉक और letके दायरे वाला निकटतम संलग्न ब्लॉक है, जो एक समारोह ब्लॉक की तुलना में छोटे हो सकता है। यदि किसी भी ब्लॉक के बाहर दोनों ग्लोबल हैं। चलिए एक उदाहरण देखें:

उदाहरण 1:

मेरे दोनों उदाहरणों में मेरे पास एक फ़ंक्शन है myfuncmyfuncएक चर वैरिएबल के myvarबराबर है 10. मेरे पहले उदाहरण में मैं myvarजांचता हूं कि 10 ( myvar==10) के बराबर है या नहीं । यदि हां, तो मैं एग्रीयन कीवर्ड myvarका उपयोग करके एक चर (अब मेरे पास दो myvar चर) घोषित varकरता है और इसे एक नया मान (20) असाइन करता है। अगली पंक्ति में मैं अपने कंसोल पर अपना मान प्रिंट करता हूं। सशर्त ब्लॉक के बाद मैं फिर से myvarअपने कंसोल पर मूल्य मुद्रित करता हूं। यदि आप आउटपुट को देखते हैं myfunc, तो myvarमान 20 के बराबर है।

उदाहरण 2 :var मेरे सशर्त ब्लॉक में कीवर्ड का उपयोग करने के बजाय मेरे दूसरे उदाहरण में मैं कीवर्ड myvarका उपयोग करके घोषणा करता हूं let। अब जब मैं कॉल करता myfuncहूं तो मुझे दो अलग-अलग आउटपुट मिलते हैं: myvar=20और myvar=10

तो अंतर बहुत सरल यानी इसका दायरा है।


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

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

उपर्युक्त प्रक्रिया फ़ंक्शंस की वांछित सरणी उत्पन्न नहीं करती है क्योंकि i दायरा ब्लॉक के पुनरावृत्ति से परे फैला हुआ है जिसमें प्रत्येक फ़ंक्शन बनाया गया था। इसके बजाय, लूप के अंत में, प्रत्येक फ़ंक्शन के बंद होने पर i adderFunctions में प्रत्येक अज्ञात फ़ंक्शन के लिए लूप (1000) के अंत में मूल्य का संदर्भ देता adderFunctions । यह वही नहीं है जो हम चाहते थे: अब हमारे पास बिल्कुल वही व्यवहार के साथ स्मृति में 1000 अलग-अलग फ़ंक्शन हैं। और यदि हम बाद में i मूल्य को अपडेट करते हैं, तो उत्परिवर्तन सभी adderFunctions को प्रभावित करेगा।

हालांकि, हम फिर से कीवर्ड का उपयोग करके पुनः प्रयास कर सकते हैं:

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

इस बार, i लूप के प्रत्येक पुनरावृत्ति पर वापसी करता i । प्रत्येक फ़ंक्शन अब फ़ंक्शन के निर्माण के समय i मान रखता है, और adderFunctions कार्य adderFunctions व्यवहार करता है।

अब, छवि दो व्यवहारों को मिश्रित करती है और आप शायद देखेंगे कि नए स्क्रिप्ट को मिश्रित करने और उसी स्क्रिप्ट में पुराने var साथ const करने की अनुशंसा क्यों नहीं की जाती है। ऐसा करने से परिणाम कुछ शानदार भ्रमित कोड हो सकता है।

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

ऐसा मत होने दो। एक लिटर का प्रयोग करें।

नोट: यह एक शिक्षण उदाहरण है जिसका उद्देश्य लूप में var/ letव्यवहार को प्रदर्शित करना है और फ़ंक्शन क्लोजर के साथ करना भी समझना आसान होगा। यह संख्या जोड़ने के लिए एक भयानक तरीका होगा। लेकिन अज्ञात फ़ंक्शन क्लोजर में डेटा कैप्चर करने की सामान्य तकनीक अन्य संदर्भों में असली दुनिया में सामने आ सकती है। YMMV।


निम्नलिखित दो कार्य अंतर दिखा सकते हैं:

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}

कुछ सूक्ष्म मतभेद हैं - स्कोपिंग को वैरिएबल स्कोपिंग की तरह व्यवहार करने let , कम या ज्यादा किसी अन्य भाषा में।

उदाहरण के लिए यह संलग्न ब्लॉक को स्कॉप्स करता है, वे घोषित होने से पहले मौजूद नहीं होते हैं, इत्यादि।

हालांकि यह ध्यान देने योग्य है कि let केवल नए जावास्क्रिप्ट कार्यान्वयन का हिस्सा हैं और इसमें ब्राउज़र समर्थन की अलग-अलग डिग्री हैं।


ईसीएमएस्क्रिप्ट 6 ने "चलो" के अलावा "कॉन्स्ट" अन्य चर को घोषित करने के लिए एक और कीवर्ड जोड़ा।

"Var" पर "let" और "const" के परिचय का प्राथमिक लक्ष्य पारंपरिक शब्दावली स्कोपिंग के बजाय ब्लॉक स्कोपिंग होना है। यह आलेख "var" और "let" के बीच बहुत संक्षिप्त अंतर बताता है और इसमें "कॉन्स्ट" पर चर्चा भी शामिल है


कुछ हैक्स के साथ let:

1।

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2।

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

3।

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

गेटटर और सेटर के साथ let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)

समारोह वीएस ब्लॉक गुंजाइश:

के बीच मुख्य अंतर varऔर letचर के साथ घोषणा की कि है varकर रहे हैं समारोह scoped । जबकि ब्लॉक घोषित ब्लॉक ब्लॉकlet हैं । उदाहरण के लिए:

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

के साथ चर var:

जब पहला फ़ंक्शन testVarवैरिएबल foo कहलाता है, जिसे घोषित किया जाता है var, अभी भी ifकथन के बाहर पहुंच योग्य है । यह चर फंक्शन के दायरे में हर जगहfoo उपलब्ध होगा ।testVar

के साथ चर let:

जब दूसरे फ़ंक्शन testLetको वेरिएबल बार कहा जाता है, जिसे घोषित किया जाता है let, केवल ifकथन के अंदर ही पहुंच योग्य होता है । क्योंकि चर के साथ घोषित letकर रहे हैं ब्लॉक scoped (जहां एक ब्लॉक कर्ली कोष्ठक के बीच कोड है जैसे if{}, for{}, function{})।

let चर नहीं मिलते हैं:

बीच एक और अंतर varऔर letसाथ साथ घोषित चर है let है फहराया नहीं । इस व्यवहार को चित्रित करने का सबसे अच्छा तरीका उदाहरण है:

घुमावदार let नहीं है के साथ चर :

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

साथ चर var करते फहराया हो:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

ग्लोबल से letजुड़ा नहीं है window:

letग्लोबल स्कोप (जो कोड है जो फ़ंक्शन में नहीं है) में घोषित एक चर वैश्विक windowवस्तु पर एक संपत्ति के रूप में नहीं जोड़ा जाता है । उदाहरण के लिए (यह कोड वैश्विक दायरे में है):

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


कब letइस्तेमाल किया जाना चाहिए var?

जब भी आप कर सकते हैं letपर प्रयोग करें varक्योंकि यह बस अधिक विशिष्ट scoped है। यह संभावित नामकरण विवादों को कम करता है जो बड़ी संख्या में चर से निपटने के दौरान हो सकता है। varजब आप ग्लोबल वैरिएबल को windowऑब्जेक्ट पर स्पष्ट रूप से होना चाहते हैं तो इसका उपयोग किया जा सकता है (यदि यह वास्तव में आवश्यक है तो सावधानी से विचार करें)।


let

ब्लॉक दायरा

let कीवर्ड का उपयोग करके घोषित वैरिएबल ब्लॉक-स्कोप्ड हैं, जिसका अर्थ है कि वे केवल उस ब्लॉक में उपलब्ध हैं जिसमें उन्हें घोषित किया गया था।

शीर्ष स्तर पर (एक समारोह के बाहर)

शीर्ष स्तर पर, वैरिएबल का उपयोग करके घोषित किया गया है कि वैश्विक वस्तु पर गुण न बनाएं।

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

एक समारोह के अंदर

एक समारोह के अंदर (लेकिन एक ब्लॉक के बाहर), let var के समान दायरा है।

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

एक ब्लॉक के अंदर

किसी ब्लॉक के अंदर let का उपयोग करके घोषित वैरिएबल को उस ब्लॉक के बाहर एक्सेस नहीं किया जा सकता है।

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

एक पाश के अंदर

लूप इन लूप के साथ घोषित वैरिएबल को केवल उस लूप के अंदर संदर्भित किया जा सकता है।

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

बंद के साथ लूप्स

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

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

अस्थायी मृत क्षेत्र

अस्थायी मृत क्षेत्र की वजह से, घोषित करने से पहले घोषित चर को एक्सेस नहीं किया जा सकता है। ऐसा करने का प्रयास करने से एक त्रुटि फेंकता है।

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

कोई पुन: घोषणा नहीं

आप let का उपयोग कर एक ही चर कई बार घोषित नहीं कर सकते हैं। आप वही पहचानकर्ता के रूप में एक वैरिएबल घोषित कर सकते हैं जो एक और वैरिएबल के रूप में घोषित किया गया था जिसे var का उपयोग करके घोषित किया गया था।

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

कॉन्स को ब्लॉक-स्कोप्ड के समान ही है और टीडीजेड है। हालांकि, दो चीजें अलग हैं।

कोई पुनः आवंटन नहीं

कास्ट का उपयोग कर घोषित वैरिएबल फिर से असाइन नहीं किया जा सकता है।

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

ध्यान दें कि इसका मतलब यह नहीं है कि मूल्य अपरिवर्तनीय है। इसकी संपत्तियों को अभी भी बदला जा सकता है।

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

यदि आप एक अपरिवर्तनीय वस्तु चाहते हैं, तो आपको ऑब्जेक्ट.फ्रीज़ Object.freeze() उपयोग करना चाहिए।

प्रारंभकर्ता की आवश्यकता है

const का उपयोग करके एक चर घोषित करते समय आपको हमेशा एक मान निर्दिष्ट करना होगा।

const a; // SyntaxError: Missing initializer in const declaration

यदि मैं चश्मे को सही ढंग से पढ़ता हूं तो let शुक्रिया को केवल निजी सदस्यों को अनुकरण करने के लिए उपयोग किए जाने वाले स्वयं के आविष्कार कार्यों से बचने के लिए लीवरेज किया जा सकता है - एक लोकप्रिय डिजाइन पैटर्न जो कोड पठनीयता को कम करता है, डीबगिंग को जटिल करता है, जो वास्तविक कोड सुरक्षा या अन्य लाभ नहीं जोड़ता है - सिवाय किसी को संतुष्ट करने के अलावा अर्थशास्त्र के लिए इच्छा, तो इसका उपयोग बंद करो। / शेख़ी

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

'देखें निजी इंटरफेस की नकल '


कुछ उदाहरणों के साथ let कीवर्ड का स्पष्टीकरण यहां दिया गया है

var की तरह बहुत काम करता है। मुख्य अंतर यह है कि एक var चर का दायरा पूरे संलग्न कार्य है

विकिपीडिया पर यह तालिका दिखाती है कि कौन से ब्राउज़र जावास्क्रिप्ट 1.7 का समर्थन करते हैं।

ध्यान दें कि केवल मोज़िला और क्रोम ब्राउज़र ही इसका समर्थन करते हैं। आईई, सफारी, और संभावित रूप से अन्य नहीं करते हैं।





let