एक फ़ंक्शन के अंदर जाने के लिए घोषित किए गए कुछ चर दूसरे फ़ंक्शन में कैसे उपलब्ध होते हैं, जबकि अन्य एक संदर्भ त्रुटि के परिणामस्वरूप होते हैं?


158

मैं समझ नहीं पा रहा हूं कि किसी फ़ंक्शन के अंदर घोषित होने पर चर इतने अजीब क्यों होते हैं।

  1. में firstसमारोह के साथ मैं घोषित letचर bऔर cमूल्य के साथ 10 :

    b = c = 10;

    में secondसमारोह मैं दिखाने:

    b + ", " + c

    और यह दिखाता है:

    10, 10
  2. इसके अलावा firstसमारोह में मैं aमूल्य 10 के साथ घोषणा करता हूं :

    let a = b = c = 10;

    लेकिन secondफ़ंक्शन में यह एक त्रुटि दिखाता है:

    परिवर्तनशील नहीं मिल सकता है: a

  3. अब firstफ़ंक्शन में मैं dमूल्य 20 के साथ घोषित करता हूं :

    var d = 20;

    लेकिन secondफ़ंक्शन में यह पहले की तरह ही त्रुटि दिखाता है, लेकिन चर के साथ d:

    परिवर्तनशील नहीं मिल सकता है: d

उदाहरण:

function first() {
  let a = b = c = 10;
  var d = 20;
  second();
}

function second() {
  console.log(b + ", " + c); //shows "10, 10"

  try{ console.log(a); }  // Rreference error
  catch(e){ console.error(e.message) }

  try{ console.log(d); } // Reference error
  catch(e){ console.error(e.message) }
}
first()


31
आप वैश्विक घोषणा कर रहे हैं, क्योंकि bऔर cउपसर्ग के साथ नहीं कर रहे हैं varकीवर्ड। aऔर करने के dलिए स्थानीय हैं first
व्लाज

1
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; क्या यह एक अच्छा साक्षात्कार प्रश्न होगा, इस बारे में एक बातचीत में बातचीत को संग्रहीत किया गया है ।
कोड़ी ग्रे

1
यह मुझे Visual Basic में एक समान स्थिति की याद दिलाता है; Dim Apple, Banana, Pear As Fruitका मतलब है Dim Apple / Dim Banana / Dim Pear As Fruit, और नहीं Dim Apple As Fruit / ...
एरिक लिपर्ट

जवाबों:


179

ऐसा इसलिए है क्योंकि आप वास्तव में कह रहे हैं:

c = 10;
b = c;
let a = b;

और न कि तुम क्या सोचते हो तुम कह रहे हो, जो है:

let a = 10;
let b = 10;
let c = 10;

आप देखेंगे कि आप अपनी श्रृंखला में चाहे जितने भी चर जोड़ लें, यह केवल पहला (ए) होगा जो त्रुटि का कारण बनता है।

इसका कारण यह है कि "" अपने वैरिएबल को ब्लॉक (या, "स्थानीय रूप से", अधिक या कम अर्थ "कोष्ठक") में स्कोप करें, जिसमें आप इसे घोषित करते हैं।

यदि आप "let" के बिना एक वैरिएबल घोषित करते हैं, तो यह वैरिएबल को वैश्विक रूप से स्कोप करता है।

इसलिए, उस फ़ंक्शन में जहां आप अपने चर सेट करते हैं, सब कुछ मूल्य 10 प्राप्त करता है (यदि आप एक ब्रेकपॉइंट लगाते हैं तो आप डिबगर में इसे देख सकते हैं)। यदि आप उस पहले फ़ंक्शन में a, b, c के लिए कंसोल लॉग लगाते हैं, तो सब ठीक है।

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

ऐसा इसलिए है क्योंकि, "केवल" केवल आवेदन करें (इसलिए केवल स्थानीय रूप से स्कोप) फिर से वारबल - फिर से, जो तकनीकी रूप से अंतिम घोषित किया जाना है और श्रृंखला में एक मूल्य सौंपा गया है। बाकी तकनीकी रूप से उनके सामने "लेट" नहीं है। तो उन्हें तकनीकी रूप से वैश्विक स्तर पर घोषित किया जाता है (जो कि वैश्विक वस्तु पर है), यही कारण है कि वे आपके दूसरे फ़ंक्शन में दिखाई देते हैं।

इसे आज़माएं: "लेट" कीवर्ड को हटा दें। अब आपके सभी संस्करण उपलब्ध होंगे।

"var" में एक समान स्थानीय-स्कोप प्रभाव होता है, लेकिन यह इस बात में भिन्न होता है कि चर को "फहराया" कैसे जाता है, जो कुछ ऐसा है जिसे आपको निश्चित रूप से समझना चाहिए, लेकिन जो सीधे आपके प्रश्न के साथ शामिल नहीं है।

(बीटीडब्लू, यह सवाल पर्याप्त समर्थक जेएस देवों को इसे एक अच्छा बनाने के लिए स्टंप करेगा)।

दृढ़ता से सुझाव दें कि आप भिन्नता के साथ समय बिताएं कि जेएस में चर कैसे घोषित किए जा सकते हैं: बिना कीवर्ड के, "लेट" और "वर्जन" के साथ।


4
यह एक साथ प्रोग्रामिंग के बारे में सबसे अच्छी और बुरी बात है: कंप्यूटर वही करेगा जो आप इसे करने के लिए कहते हैं। जरूरी नहीं कि आप इसे करने के लिए क्या कहें। कार्यक्रम परिपूर्ण हैं। हम समस्याएं पैदा करते हैं।
नीट द डार्क एबसोल

8
@Thevs क्यों आप की सिफारिश करते हैं varसे अधिक letइस जवाब के संदर्भ में? मुझे समझ नहीं आ रहा है।
केलकोन

4
@ मैं आपके साथ असहमत हूं। varलापरवाही बरतने पर कीड़े पड़ सकते हैं। इस फिडेल की
Cid

2
@ इस मामले varमें कोई फायदा नहीं है let? मुझे स्पष्ट करें: एक आधुनिक संदर्भ जब दोनों विकल्प हैं और मैं कोड के लिए कह रहा हूं कि एक लिखना चाहिए । जब मैंने इससे पहले पूछा है, तो मुझे "आप के साथ एक चर को फिर से घोषित कर सकते हैं" के बारे में जवाब मिला है varजिस स्थिति में मुझे लोगों को याद दिलाना होगा कि आपको चर घोषित नहीं करना चाहिए । यह कोड के तर्क में एक बग या त्रुटि है - इसलिए पुन: घोषणा का लाभ यह है ... कि यह आपको गलती कोड लिखने की अनुमति देता है। मैं अभी तक किसी भी समझदार कारण को देखने के पक्ष में हूं varजब letकोई विकल्प भी हो।
व्लाज

2
जावास्क्रिप्ट के खिलाफ एक और निशान चाक। जब तक स्थानीय घोषित नहीं किया जाता तब तक सभी चर वैश्विक होते हैं। :(
जेरे

68

समारोह में first(), चर bऔर cका उपयोग किए बिना मक्खी पर बनाए जाते हैं, varया let

let a = b = c = 10; // b and c are created on the fly

से अलग है

let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)

वे निहित वैश्विक हो जाते हैं। इसलिए वे अंदर उपलब्ध हैंsecond()

से प्रलेखन

एक अघोषित चर के लिए एक मूल्य निर्दिष्ट करना यह असाइनमेंट निष्पादित होने पर एक वैश्विक चर (यह वैश्विक वस्तु की संपत्ति बन जाता है) के रूप में बनाता है।

इससे बचने के लिए, आप "use strict"एक अघोषित चर का उपयोग करते समय त्रुटियां प्रदान करेंगे

"use strict"; // <-------------- check this

function first() {
   /*
    * With "use strict" c is not defined.
    * (Neither is b, but since the line will be executed from right to left,
    * the variable c will cause the error and the script will stop)
    * Without, b and c become globals, and then are accessible in other functions
    */
   let a = b = c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //reference error
   console.log(a); //reference error
   console.log(d); //reference error
}

first();


15
इसके अलावा: let a = 10, b = 10, c = 10;या let a, b, c; a = b = c = 10;अन्यथा चर घोषित करने का सही तरीका होगा।
रिकाॅर्ड एलिआमा

तो सख्त मोड के साथ, चर b के बारे में क्या?
टिक 20

2
@ Tick20 चर bका मूल्यांकन / पहुंच नहीं होगी, त्रुटि लाइन पर होगी let a = b = c = 10;, दाएं से बाएं पढ़ा जाएगा । cपहला चर होने के कारण ReferenceError, शेष पंक्ति को निष्पादित नहीं किया जाएगा (स्क्रिप्ट बंद हो गई है)
Cid

2
कुछ ऐसा let a = 10, b = a, c = b;ही मान्य है
कददठ

8
मुख्य रूप से "सख्त का उपयोग करें" के लिए उत्कीर्ण। एक साक्षात्कार प्रश्न के संदर्भ में, यह भी इस कोड पर मेरी टिप्पणी की शुरुआत होगी।
पच0

23

अजीब बातें करने से पहले, आइए पहले कुछ मूल बातें जानते हैं:

var और let दोनों का उपयोग जावास्क्रिप्ट में चर घोषणा के लिए किया जाता है। उदाहरण के लिए,

var one = 1;
let two = 2;

चर का उपयोग किए बिना varया के बिना भी घोषित किया जा सकता है let। उदाहरण के लिए,

three = 3;

अब उपरोक्त दृष्टिकोणों में अंतर यह है कि:

var फ़ंक्शन स्कॉप किया गया है

तथा

let ब्लॉक स्कूप्ड है।

जबकि बिना var/ letकीवर्ड के घोषित किए गए चर का दायरा वैश्विक घोषित होने के बावजूद, जहां यह घोषित है।

वैश्विक चर को वेब पेज में कहीं से भी एक्सेस किया जा सकता है (अनुशंसित नहीं क्योंकि ग्लोबल्स को गलती से संशोधित किया जा सकता है)।

अब इन अवधारणाओं के अनुसार आइए प्रश्न में कोड पर एक नजर डालते हैं:

 function first() {
   let a = b = c = 10;
   /* The above line means:
    let a=10; // Block scope
    b=10; // Global scope
    c=10; // Global scope
    */

   var d = 20; // Function scope
   second();
}

function second() {
   alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
   alert(a); // Error not accessible because block scope has ended
   alert(d); // Error not accessible because function scope has ended
}


2
मुझे खेद है, लेकिन मेरा ऐसा कोई इरादा नहीं था, ऐसा ही कुछ हो सकता है क्योंकि हमने एक ही स्रोत से जानकारी एकत्र की हो सकती है।
फटीमासजाद

2
ऐसा हो सकता है कि दोनों उत्तरों में स्पष्ट उद्धरण के बिना एक ही मूल स्रोत से कॉपी की गई सामग्री हो - संभवतः tutorialsteacher.com/javascript/javascript-variable । साहित्यिक चोरी की उपस्थिति स्पष्ट है, क्योंकि एक व्याकरणिक त्रुटि मूल से पुन: प्रस्तुत की जाती है - " varकीवर्ड के बिना घोषित किए गए चरों की गुंजाइश वैश्विक रूप से गैर-जिम्मेदार हो जाती है जहां यह घोषित किया जाता है कि" या तो "गुंजाइश बननी चाहिए ..." या " scopes ... बन " । किसी और के सटीक शब्दों का उपयोग करने के लिए प्रशस्ति पत्र की आवश्यकता होती है, चाहे वह यहां से हो या कहीं और। meta.stackexchange.com/q/160071/211183
माइकल - sqlbot 20

धन्यवाद दोस्तों, मैंने स्रोत के लिए एक संदर्भ लिंक जोड़ा है।
फटीमासजाद

6

letकीवर्ड का उपयोग करने वाले वेरिएबल्स केवल ब्लॉक के दायरे में उपलब्ध होने चाहिए और बाहरी फ़ंक्शन में उपलब्ध नहीं होने चाहिए ...

प्रत्येक चर जिसे आप उस तरीके से घोषित कर रहे हैं वह उपयोग नहीं कर रहा है letया नहीं var। आप चरों की घोषणा में अल्पविराम याद कर रहे हैं।

यह कीवर्ड के बिना एक चर घोषित करने के लिए अनुशंसित नहीं हैvar । यह गलती से एक मौजूदा वैश्विक चर को अधिलेखित कर सकता है। varकीवर्ड के बिना घोषित किए गए वैरिएबल का दायरा वैश्विक घोषित होने के बावजूद कि वह कहां घोषित किया गया है। ग्लोबल वेरिएबल को वेब पेज में कहीं से भी एक्सेस किया जा सकता है।

function first() {
   let a = 10;
   let b = 10;
   let c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //shows "10, 10"
   console.log(a); //reference error
   console.log(d); //reference error
}

first();


3

इसका कारण यह है कि जब आप उपयोग नहीं करते हैं letया varफिर चर को मक्खी पर घोषित किया जाता है, तो बेहतर होगा कि आप निम्नलिखित की तरह घोषणा करें।

let a = 10;
let b = 10;
let c = 10;

2

अजीब मुद्दा जावास्क्रिप्ट में नियमों को काटने के कारण होता है

function first() {
   let a = b = c = 10; // a is in local scope, b and c are in global scope
   var d = 20; // d is in local scope
   second(); // will have access to b and c from the global scope
}

यह मानते हुए कि आप एक ही मूल्य (100) से आरंभिक 3 स्थानीय चर घोषित करना चाहते हैं । आपका पहला () नीचे की तरह दिखेगा। इस मामले में, दूसरे () में किसी भी चर तक पहुंच नहीं होगी क्योंकि वे पहले से स्थानीय हैं ()

function first() {
   let a = 100; // a is in local scope init to 100
   let b = a; // b is in local scope init to a
   let c = b // c is in local scope init to b

   var d = 20; // d is in local scope
   second(); // will not have access a, b, c, or d
}

हालाँकि, यदि आप वैश्विक चर चाहते हैं तो आपका पहला () नीचे जैसा दिखेगा। इस मामले में, दूसरे के पास सभी चर तक पहुंच होगी, क्योंकि वे वैश्विक दायरे में हैं

function first() {
   a = 100; // a is in global scope
   b = a; // b is in global scope
   c = b // c is in global scope

   d = 20; // d is in global scope
   second(); // will have access to a, b, c, and d from the global scope
}

स्थानीय चर (उर्फ कोड ब्लॉक में सुलभ हैं जहां उन्हें घोषित किया गया है)।
एक कोड ब्लॉक किसी भी {} कोड के बीच की रेखा के साथ है।

  • फ़ंक्शन () {var, let, const यहाँ पूरे फ़ंक्शन के लिए सुलभ है},
  • के लिए () {var यहां बाहरी दायरे के लिए सुलभ है, चलो, यहां केवल const पहुंचें},
  • आदि।

वैश्विक चर (वैश्विक दायरे में सुलभ उर्फ)।
ये चर वैश्विक वस्तु से जुड़े होते हैं। वैश्विक वस्तु पर्यावरण पर निर्भर है। यह ब्राउज़रों में विंडो ऑब्जेक्ट है।

विशेष नोट: आप जावास्क्रिप्ट में वेरिएबल, वेरिएबल, कॉन्स्टेबल कीवर्ड का उपयोग किए बिना घोषित कर सकते हैं। इस तरह घोषित किया गया एक वैरिएबल वैश्विक ऑब्जेक्ट से जुड़ा हुआ है, इसलिए वैश्विक दायरे में सुलभ है।
a = 100 // is valid and is in global scope

आगे पढ़ने के लिए कुछ लेख: https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/ https://scotch.io/tutorials/understanding-scope-in-javascript https: www.digitalocean .com / समुदाय / ट्यूटोरियल / समझने-चर-गुंजाइश-उत्थापन में जावास्क्रिप्ट


0

मुख्य अंतर स्कूपिंग नियम है। Var कीवर्ड द्वारा घोषित चर को तत्काल फ़ंक्शन बॉडी (इसलिए फंक्शन स्कोप) पर स्कोप किया जाता है, जबकि वेरिएबल्स को {} (इसलिए ब्लॉक स्कोप) द्वारा निरूपित तत्काल एन्कोडिंग ब्लॉक में स्कोप किया जाता है। और जब आप कहेंगे

c = 10;
b = c;
let a = b;

c और b में जीवन काल मौज-मस्ती के रूप में है, लेकिन केवल एक ब्लॉक अवधि है और यदि आप इसे संदर्भित करके एक्सेस करने का प्रयास करते हैं, तो यह हमेशा त्रुटि दिखाता है लेकिन c और b विश्व स्तर पर हैं, इसलिए वे यह नहीं देखते हैं कि कोई फर्क नहीं पड़ता कि कितने चर जो आप अपनी श्रृंखला में जोड़ते हैं, यह केवल पहला (ए) होगा जो त्रुटि का कारण बनता है। यह इसलिए है क्योंकि "अपने" को चर को ब्लॉक (या, "स्थानीय रूप से", अधिक या कम अर्थ "कोष्ठक में") करें जिसमें आप इसे घोषित करते हैं। यदि आप "लेट" के बिना एक वैरिएबल की घोषणा करते हैं, तो यह विश्व स्तर पर वैरिएबल को स्कोप करता है। इसलिए, जिस फंक्शन में आपने अपने वेरिएबल्स को सेट किया है, वहां हर चीज की वैल्यू 10 हो जाती है (यदि आप इसे डीबगर में देख सकते हैं, तो ब्रेक-बिंदु)। यदि आप उस पहले फ़ंक्शन में a, b, c के लिए कंसोल लॉग लगाते हैं, तो सब ठीक है। लेकिन जैसे ही आप उस फ़ंक्शन को छोड़ते हैं, पहले वाला (a) - और फिर, ध्यान रखें,


0

यहाँ जावास्क्रिप्ट में चर घोषणाओं के 3 दिलचस्प पहलू हैं:

  1. var वेरिएबल के दायरे को उस ब्लॉक तक सीमित कर देता है जिसमें इसे परिभाषित किया गया है। ( 'Var' के लिए है स्थानीय गुंजाइश ।)

  2. लेट अनुमति देता है अस्थायी अधिभावी एक ब्लॉक के अंदर एक बाहरी चर के मूल्य के की ।

  3. सीधे शब्दों में बिना एक चर घोषित करने वर या जाने चर वैश्विक बनाने, जहां यह घोषित किया जाता है की परवाह किए बिना होगा।

यहाँ के एक डेमो है देना है, जो भाषा के लिए नवीनतम इसके अतिरिक्त है:

// File name:  let_demo.js

function first() {
   a = b = 10
   console.log("First function:    a = " + a)
   console.log("First function:    a + b = " + (a + b))
}

function second() {
    let a = 5
    console.log("Second function:    a = " + a)
    console.log("Second function:    a + b = " + (a + b))
}

first()   

second()

console.log("Global:    a = " + a)
console.log("Global:    a + b = " + (a + b))

आउटपुट:

$ node let_demo.js 

First function:    a = 10
First function:    a + b = 20

Second function:    a = 5
Second function:    a + b = 15

Global:    a = 10
Global:    a + b = 20

स्पष्टीकरण:

वैरिएबल a और b बिना 'या' कीवर्ड के ' पहले ' () के अंदर डिलीट हो गए थे ।

इसलिए, और बी वैश्विक हैं, और इसलिए, पूरे कार्यक्रम में सुलभ हैं।

'सेकंड' नाम के फंक्शन में , स्टेटमेंट 'let a a = 5' अस्थायी रूप से ' a ' से ' 5 ' का मान सेट करता है , केवल फंक्शन के दायरे में।

वैश्विक दायरे में ' सेकंड () ', IE के दायरे के बाहर, ' a ' का मान पहले के रूप में परिभाषित किया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.