आश्चर्य है कि वैश्विक चर का जावास्क्रिप्ट में अपरिभाषित मूल्य है


87

आज, मैं पूरी तरह से आश्चर्यचकित हो गया जब मैंने देखा कि एक वैश्विक चर का undefinedकिसी निश्चित मामले में मूल्य है।

उदाहरण:

var value = 10;
function test() {
    //A
    console.log(value);
    var value = 20;

    //B
    console.log(value);
}
test();

के रूप में उत्पादन देता है

undefined
20

यहाँ, वैश्विक मान के अनुसार जावास्क्रिप्ट इंजन क्यों है undefined। मुझे पता है कि जावास्क्रिप्ट एक व्याख्या की गई भाषा है। यह फ़ंक्शन में चर पर विचार करने में सक्षम कैसे है?

क्या यह जावास्क्रिप्ट इंजन से नुकसान है?

जवाबों:


175

इस घटना को इस प्रकार से जाना जाता है: जावास्क्रिप्ट परिवर्तनीय उत्थापन

किसी भी बिंदु पर आप अपने फ़ंक्शन में वैश्विक चर तक नहीं पहुंच रहे हैं; आप केवल कभी-कभी स्थानीय valueचर पर पहुँच रहे हैं ।

आपका कोड निम्नलिखित के बराबर है:

var value = 10;

function test() {
    var value;
    console.log(value);

    value = 20;
    console.log(value);
}

test();

फिर भी आप हैरान हो रहे हैं undefined?


स्पष्टीकरण:

यह कुछ ऐसा है जो हर जावास्क्रिप्ट प्रोग्रामर को जल्द या बाद में टक्कर देता है। सीधे शब्दों में कहें, तो आप जो भी चर घोषित करते हैं, वह हमेशा आपके स्थानीय बंद के शीर्ष पर फहराया जाता है। इसलिए, भले ही आपने पहली console.logकॉल के बाद अपना वैरिएबल घोषित किया हो, फिर भी यह माना जाता है कि आपने इससे पहले इसे घोषित किया था।
हालाँकि, केवल घोषणा का हिस्सा फहराया जा रहा है; दूसरी ओर, असाइनमेंट, नहीं है।

इसलिए, जब आपने पहली बार फोन किया था console.log(value), तो आप अपने स्थानीय रूप से घोषित चर का संदर्भ दे रहे थे, जिसे अभी तक कुछ भी नहीं सौंपा गया है; इसलिए undefined

यहाँ एक और उदाहरण है :

var test = 'start';

function end() {
    test = 'end';
    var test = 'local';
}

end();
alert(test);

आपको क्या लगता है कि यह अलर्ट करेगा? नहीं, बस पर नहीं पढ़ें, इसके बारे में सोचो। का मूल्य क्या है test?

अगर आपने इसके अलावा कुछ भी कहा start, तो आप गलत थे। उपरोक्त कोड इसके बराबर है:

var test = 'start';

function end() {
    var test;
    test = 'end';
    test = 'local';
}

end();
alert(test);

ताकि वैश्विक वैरिएबल कभी प्रभावित न हो।

जैसा कि आप देख सकते हैं, कोई फर्क नहीं पड़ता कि आपने अपनी परिवर्तनीय घोषणा कहां रखी है, यह हमेशा आपके स्थानीय बंद होने के शीर्ष पर फहराया जाता है।


पक्षीय लेख:

यह फ़ंक्शन पर भी लागू होता है।

कोड के इस टुकड़े पर विचार करें :

test("Won't work!");

test = function(text) { alert(text); }

जो आपको एक संदर्भ त्रुटि देगा:

बिना संदर्भित संदर्भ: परीक्षण परिभाषित नहीं है

यह बहुत सारे डेवलपर्स को बंद कर देता है, क्योंकि कोड का यह टुकड़ा ठीक काम करता है:

test("Works!");

function test(text) { alert(text); }

जैसा कि कहा गया है, इसका कारण यह है कि असाइनमेंट का हिस्सा फहराया नहीं गया है । इसलिए पहले उदाहरण में, जब test("Won't work!")चलाया गया था, testचर पहले ही घोषित किया जा चुका है, लेकिन अभी तक इसे सौंपा गया कार्य नहीं है।

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


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


27
यह एक अच्छी व्याख्या है। हालाँकि, मुझे एक समाधान याद है जहाँ आप किसी फ़ंक्शन के अंदर वैश्विक चर तक पहुँच सकते हैं।
डुकेस

1
@ DuKes0mE - आप हमेशा एक फ़ंक्शन के अंदर वैश्विक चर का उपयोग कर सकते हैं।
जोसेफ सिलबर

3
हां, और ए मामले में उद्घाटन पोस्ट से काम नहीं कर रहा है और इसके अपरिभाषित नहीं कह रहा है? मैं समझता हूं, कि इसकी व्याख्या वैश्विक के बजाय स्थानीय संस्करण के रूप में की जाएगी, लेकिन फिर यह वैश्विक कैसे होगा?
DuKes0mE

4
वैश्विक वैरिएबल का उपयोग करने के लिए उपयोग करें window.value
Venkat Reddy

1
चर उत्थापन की यह शैली कब लागू की गई थी? क्या यह हमेशा जावास्क्रिप्ट में मानक रहा है?
दिस्किम

54

मैं कुछ निराश था कि यहाँ समस्या को समझाया गया है, लेकिन किसी ने भी समाधान का प्रस्ताव नहीं दिया। यदि आप फ़ंक्शन के बिना एक वैश्विक वैरिएबल को एक्सेस करना चाहते हैं, तो फ़ंक्शन को अपरिभाषित स्थानीय संस्करण बनाने के बिना, पहले संदर्भ को देखेंwindow.varName


8
हाँ, यह बेकार है कि अन्य लोगों ने एक समाधान का प्रस्ताव नहीं किया क्योंकि यह Google परिणामों में पहला परिणाम है। उन्होंने ALMOST को इस सवाल का जवाब देने के बारे में पूछा कि यह js इंजन में
ख़राब

2
सैद्धांतिक ज्ञान और श करने के बीच का अंतर। उस उत्तर के लिए धन्यवाद!
hansTheFranz

मेरे लिए, यह एक गलती है कि मैं किसी भी समारोह में कहीं भी एक वैश्विक नाम को भिन्न करता हूं। भ्रम के लिए बनाता है, कम से कम। Google खोज की आवश्यकता के लिए, सबसे खराब रूप से बनाता है। धन्यवाद
dcromley

जावास्क्रिप्ट मुझे हर रोज आश्चर्यचकित करता है जो गुजरता है। धन्यवाद आदमी, जवाब मददगार था।
रफ

समाधान के लिए धन्यवाद, मुझे यह एक वैश्विक संस्करण के अपरिभाषित होने के बाद मिला लेकिन केवल सफारी में। अन्य 'शामिल' फाइलें और वैश्विक संस्करण जैसे कि 'google' को दिखाया गया है, इसलिए मैंने उपयोग किए गए दृष्टिकोण की प्रतिलिपि बनाई है: window.globalVarFromJS = window.globalVarFromJS || {}; तब मुझे आपका हल मिला तो मैंने सोचा कि मैं इसे जोड़ दूंगा।
राल्फ हिंकले

10

जावास्क्रिप्ट में चर हमेशा समारोह चौड़ा गुंजाइश है। भले ही वे फ़ंक्शन के बीच में परिभाषित किए गए थे, वे पहले दिखाई दे रहे हैं। फंक्शन उत्थापन के साथ इसी तरह की घटनाएं देखी जा सकती हैं।

कहा जा रहा है, पहले चर को console.log(value)देखता है value(आंतरिक एक जो बाहरी छाया करता है value), लेकिन इसे अभी तक प्रारंभ नहीं किया गया है। आप इसके बारे में सोच सकते हैं, जैसे कि सभी चर घोषणाओं परोक्ष समारोह (की शुरुआत करने के लिए ले जाया गया था नहीं , भीतरी सबसे कोड ब्लॉक), जबकि परिभाषाएँ एक ही जगह पर छोड़ दिया जाता है।

यह सभी देखें


मैं हमेशा सरल शब्दों को प्यार करता हूँ +1 :)
जशवंत

3

एक वैश्विक चर है value, लेकिन जब नियंत्रण testफ़ंक्शन में प्रवेश करता है, तो एक और valueचर घोषित किया जाता है, जो वैश्विक छाया देता है। चूंकि जावास्क्रिप्ट में चर घोषणाएं ( लेकिन असाइनमेंट नहीं ) उस दायरे के शीर्ष पर फहराए जाते हैं जिसमें वे घोषित किए जाते हैं:

//value == undefined (global)
var value = 10;
//value == 10 (global)

function test() {
    //value == undefined (local)
    var value = 20;
    //value == 20 (local)
}
//value == 10 (global)

ध्यान दें कि वही फ़ंक्शन घोषणाओं का सच है, जिसका अर्थ है कि आप अपने कोड में परिभाषित होने से पहले फ़ंक्शन को कॉल कर सकते हैं:

test(); //Call the function before it appears in the source
function test() {
    //Do stuff
}

यह भी ध्यान देने योग्य है कि जब आप दोनों को एक फ़ंक्शन एक्सप्रेशन में जोड़ते हैं, तो वेरिएबल undefinedतब तक होगा जब तक असाइनमेंट नहीं हो जाता है, इसलिए आप तब तक फ़ंक्शन को कॉल नहीं कर सकते हैं:

var test = function() {
    //Do stuff
};
test(); //Have to call the function after the assignment

0
  1. बाहरी चर (केवल वैश्विक गुंजाइश नहीं) तक पहुंच रखने का सबसे सरल तरीका, कार्यों में समान नाम के तहत उन्हें फिर से घोषित न करने का प्रयास करना है; बस वहाँ var का उपयोग न करें । उचित वर्णनात्मक नामकरण नियमों के उपयोग की सलाह दी जाती है। उन लोगों के साथ, मूल्य जैसे नामित चर के साथ समाप्त करना मुश्किल होगा (यह पहलू जरूरी नहीं कि उदाहरण में संबंधित हो क्योंकि यह चर नाम सादगी के लिए दिया गया है)।

  2. यदि फ़ंक्शन का कहीं और पुन: उपयोग किया जा सकता है और इसलिए कोई गारंटी नहीं है कि बाहरी चर वास्तव में उस नए संदर्भ में परिभाषित किया गया है, तो एवल फ़ंक्शन का उपयोग किया जा सकता है। यह इस ऑपरेशन में धीमा है, इसलिए इसे प्रदर्शन-मांग कार्यों के लिए अनुशंसित नहीं किया गया है:

    if (typeof variable === "undefined")
    {
        eval("var variable = 'Some value';");
    }
    
  3. यदि आप जिस बाहरी स्कोप वैरिएबल को एक्सेस करना चाहते हैं, उसे एक नामित फ़ंक्शन में परिभाषित किया गया है, तो यह फ़ंक्शन को पहले स्थान पर संलग्न किया जा सकता है और फिर कोड में कहीं से भी एक्सेस किया जा सकता है - यह गहरी नेस्टेड फ़ंक्शन या इवेंट हैंडलर से बाहर हो बाकि सब कुछ। ध्यान दें कि संपत्तियों तक पहुँचने का तरीका धीमा है और आपको अपने प्रोग्राम को बदलने के तरीके की आवश्यकता होगी, इसलिए यह तब तक अनुशंसित नहीं है जब तक कि यह वास्तव में आवश्यक न हो: फ़ंक्शन के गुणों के रूप में चर (JSFiddle) :

    // (the wrapper-binder is only necessary for using variables-properties
    // via "this"instead of the function's name)
    var functionAsImplicitObjectBody = function()
    {
        function someNestedFunction()
        {
            var redefinableVariable = "redefinableVariable's value from someNestedFunction";
            console.log('--> functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty);
            console.log('--> redefinableVariable: ', redefinableVariable);
        }
        var redefinableVariable = "redefinableVariable's value from someFunctionBody";
        console.log('this.variableAsProperty: ', this.variableAsProperty);
        console.log('functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty);
        console.log('redefinableVariable: ', redefinableVariable);
        someNestedFunction();
    },
    functionAsImplicitObject = functionAsImplicitObjectBody.bind(functionAsImplicitObjectBody);
    functionAsImplicitObjectBody.variableAsProperty = "variableAsProperty's value, set at time stamp: " + (new Date()).getTime();
    functionAsImplicitObject();
    
    // (spread-like operator "..." provides passing of any number of arguments to
    // the target internal "func" function in as many steps as necessary)
    var functionAsExplicitObject = function(...arguments)
    {
        var functionAsExplicitObjectBody = {
            variableAsProperty: "variableAsProperty's value",
            func: function(argument1, argument2)
            {
                function someNestedFunction()
                {
                    console.log('--> functionAsExplicitObjectBody.variableAsProperty: ',
                        functionAsExplicitObjectBody.variableAsProperty);
                }
                console.log("argument1: ", argument1);
                console.log("argument2: ", argument2);
                console.log("this.variableAsProperty: ", this.variableAsProperty);
                someNestedFunction();
            }    
        };
        return functionAsExplicitObjectBody.func(...arguments);
    };
    functionAsExplicitObject("argument1's value", "argument2's value");
    

0

मैं वैश्विक चर के साथ भी इसी समस्या में चल रहा था। मेरी समस्या, मुझे पता चला है, HTML चर के बीच वैश्विक चर नहीं बनी रहती है।

<script>
    window.myVar = 'foo';
    window.myVarTwo = 'bar';
</script>
<object type="text/html" data="/myDataSource.html"></object>

मैंने भरी हुई HTML फ़ाइल में myVar और myVarTwo को संदर्भित करने का प्रयास किया, लेकिन अपरिभाषित त्रुटि प्राप्त की। लंबी कहानी / दिन छोटा, मुझे पता चला कि मैं चर का संदर्भ ले सकता हूं:

<!DOCTYPE html>
<html lang="en">
    <!! other stuff here !!>
    <script>

        var myHTMLVar = this.parent.myVar

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