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




14 Answers

अंतर गुंजाइश है। 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.

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

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




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

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

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

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




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

{
  let a = 123;
};

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



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

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

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




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

    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 ।




दूसरों के पहले से लिखे गए लोगों को जोड़ने के लिए यहां एक उदाहरण दिया गया है। मान लीजिए कि आप कार्यों की एक सरणी बनाना चाहते हैं, 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
}



यह भी प्रतीत होता है कि, कम से कम विजुअल स्टूडियो 2015 में, टाइपस्क्रिप्ट 1.5, "var" ब्लॉक में समान वैरिएबल नाम की कई घोषणाओं की अनुमति देता है, और "चलो" नहीं करता है।

यह एक संकलन त्रुटि उत्पन्न नहीं करेगा:

var x = 1;
var x = 2;

यह करेगा:

let x = 1;
let x = 2;



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

के बीच मुख्य अंतर 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:

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)



चलो 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:

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 का संदर्भ लें : इसे समझने के लिए चलो और समझें।




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

अंतर गुंजाइश है। 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

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




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

let x = 1;

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

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

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



Related