स्कोप में सभी वेरिएबल्स प्राप्त करना


194

क्या सभी चर प्राप्त करने का एक तरीका है जो वर्तमान में जावास्क्रिप्ट में गुंजाइश है?


कैंसॉफ्ट का अपना उत्तर दें: यह एक बिल्कुल अलग सवाल है; मैंने इसे संबोधित करने के लिए अपना उत्तर अपडेट कर दिया है।
टीजे क्राउडर

3
यह केवल एक सामान्य प्रश्न है, क्योंकि मैं एक अस्पष्ट एपीआई के साथ खराब प्रलेखन के साथ काम कर रहा हूं, तो अधिक विशिष्ट अभ्यस्त मदद नहीं कर रहा है।
इयान

आप वैश्विक चर मतलब है! आप उपयोग कर सकने योग्य वैश्विक चर प्रदर्शित कर सकते हैं for (v in this) alert(v);। हालांकि, सभी ग्लोबल्स अनगिनत नहीं हैं, और मुझे गैर-गणना योग्य लोगों की सूची प्राप्त करने का कोई मानक तरीका नहीं पता है।
जेसन ओरेंडोर्फ

2
@ जेसन - नहीं, प्रश्न स्पष्ट है। एक समारोह के अंदर दायरे में चर वैश्विक चर, शामिल होंगे this, arguments, मापदंडों और स्कोप enclosing में परिभाषित सभी चर।
टिम डाउन

2
यही कारण है कि मुझे पर्ल की प्रतीक सारणी याद आती है। इसे जावास्क्रिप्ट के भविष्य के रिलीज में जोड़ने की कोई योजना है?
डेक्सिजन

जवाबों:


84

नहीं। "स्कोप" में चर "स्कोप चेन" द्वारा निर्धारित किए जाते हैं, जो प्रोग्रामेटिक रूप से सुलभ नहीं है।

विस्तार से (इसके बारे में बहुत कुछ), ईसीएमएस्क्रिप्ट (जावास्क्रिप्ट) विनिर्देश देखें। यहां आधिकारिक पृष्ठ पर एक लिंक दिया गया है जहां आप कैनोनिकल कल्पना (एक पीडीएफ) डाउनलोड कर सकते हैं, और यहां आधिकारिक एचटीएमएल संस्करण लिंक कर सकते हैं ।

कैंसॉफ्ट पर अपनी टिप्पणी के आधार पर अपडेट करें

आपके ईवेंट फ़ंक्शन के दायरे में चर निर्धारित किए जाते हैं जहां आप अपने ईवेंट फ़ंक्शन को परिभाषित करते हैं, न कि वे इसे कैसे कहते हैं। लेकिन , आप thisकेनीटीएम (जो इंगित किया गया है for (var propName in ____)) की तर्ज पर कुछ करके आपके तर्कों के बारे में उपयोगी जानकारी प्राप्त कर सकते हैं कि क्या आपको बताएगा कि आपके लिए प्रदान की गई विभिन्न वस्तुओं ( thisऔर तर्कों; यकीन नहीं है कि वे आपको क्या तर्क देते हैं, आप उस argumentsचर के माध्यम से पता लगा सकते हैं जो प्रत्येक फ़ंक्शन के लिए स्पष्ट रूप से परिभाषित है)।

तो जहाँ आप अपने कार्य को परिभाषित करते हैं, उसके कारण जो कुछ भी इन-स्कोप है, उसके अलावा, आप यह पता लगा सकते हैं कि क्या करने से अन्य साधन उपलब्ध हैं:

var n, arg, name;
alert("typeof this = " + typeof this);
for (name in this) {
    alert("this[" + name + "]=" + this[name]);
}
for (n = 0; n < arguments.length; ++n) {
    arg = arguments[n];
    alert("typeof arguments[" + n + "] = " + typeof arg);
    for (name in arg) {
        alert("arguments[" + n + "][" + name + "]=" + arg[name]);
    }
}

(आप अधिक उपयोगी जानकारी प्राप्त करने के लिए उस पर विस्तार कर सकते हैं।)

इसके बजाय, हालांकि, मैं शायद Chrome के dev टूल जैसे डिबगर का उपयोग करूंगा (भले ही आप सामान्य रूप से Chrome का विकास के लिए उपयोग न करें) या Firebug (भले ही आप सामान्य रूप से फ़ायरफ़ॉक्स का उपयोग विकास के लिए न करें), या ओपेरा पर Dragonfly या IE पर "F12 डेवलपर टूल"। और जो भी जावास्क्रिप्ट फ़ाइलें वे आपको प्रदान करते हैं, उनके माध्यम से पढ़ें। और उन्हें उचित डॉक्स के लिए सिर पर हराया। :-)


एक साइड नोट के रूप में, Google क्रोम में फायरबग की तुलना में एक महान डिबगर है (शीर्ष पर थोड़ा और अधिक आइसिंग के साथ)।
कुंडा

4
@Swivelgames: ओह, मैं फ़ायरफ़ॉक्स + फायरबग के लिए क्रोम के देव उपकरण को बहुत पसंद करता हूं। वे 2010 में बहुत पीछे नहीं थे। :-)
टीजे क्राउडर

1
@tjcrowder वास्तव में! मैंने देखा कि उत्तर पर टाइमस्टैम्प कुछ समय पहले था :)
कुंडा

98

हालाँकि हर कोई " नहीं " का जवाब देता है और मुझे पता है कि "नहीं" सही उत्तर है, लेकिन अगर आपको वास्तव में किसी फ़ंक्शन के स्थानीय चर प्राप्त करने की आवश्यकता है, तो एक प्रतिबंधित तरीका है।

इस समारोह पर विचार करें:

var f = function() {
    var x = 0;
    console.log(x);
};

आप अपने कार्य को स्ट्रिंग में बदल सकते हैं:

var s = f + '';

आपको स्ट्रिंग के रूप में फ़ंक्शन का स्रोत मिलेगा

'function () {\nvar x = 0;\nconsole.log(x);\n}'

अब आप एस्क्रीम की तरह एक पार्सर का उपयोग फ़ंक्शन कोड को पार्स करने और स्थानीय चर घोषणाओं को खोजने के लिए कर सकते हैं ।

var s = 'function () {\nvar x = 0;\nconsole.log(x);\n}';
s = s.slice(12); // to remove "function () "
var esprima = require('esprima');
var result = esprima.parse(s);

और इसके साथ ऑब्जेक्ट खोजें:

obj.type == "VariableDeclaration"

परिणाम में (मैंने console.log(x)नीचे हटा दिया है):

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "x"
                    },
                    "init": {
                        "type": "Literal",
                        "value": 0,
                        "raw": "0"
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

मैंने इसे क्रोम, फ़ायरफ़ॉक्स और नोड में परीक्षण किया है।

लेकिन इस विधि के साथ समस्या यह है कि आपके पास केवल फ़ंक्शन में परिभाषित चर हैं। इस एक के लिए उदाहरण के लिए:

var g = function() {
    var y = 0;
    var f = function() {
        var x = 0;
        console.log(x);
    };
}

आपके पास केवल x तक पहुंच है और y नहीं । लेकिन फिर भी आप कॉलर फ़ंक्शन के स्थानीय चर खोजने के लिए एक लूप में कॉलर (आर्ग्यूमेंट्स। CCe.caller.caller.caller) की चेन का उपयोग कर सकते हैं । यदि आपके पास सभी स्थानीय चर नाम हैं, तो आपके पास गुंजाइश चर हैं । चर नामों के साथ आपके पास एक साधारण eval के साथ मूल्यों तक पहुंच है।


7
मूल समस्या से निपटने में यहाँ उत्कृष्ट तकनीक। एक उत्थान का वर्णन करता है।
गहरीकरण

4
एक कॉलर के चर आवश्यक रूप से चर चर नहीं हैं। साथ ही, कॉल श्रृंखला में स्कोप वैरिएबल आवश्यक नहीं हैं। वेरीबल्स जिन्हें बंद कर दिया गया है, उन्हें एक ऐसे कॉलर से कॉल करने पर फ़ंक्शन द्वारा संदर्भित किया जा सकता है जो परिभाषा / क्लोजर दायरे के बाहर है (और जिनके चर क्लोजर के शरीर को वापस लेने से सुलभ नहीं हैं)।
DDS

क्या आप "स्पष्ट रूप से स्पष्ट" स्पष्ट कर सकते हैं? मैंने नीचे दिए गए कोड के साथ कोशिश की, लेकिन वह दायरे में फंस नहीं सका। function getCounter(start){ return function(){ start ++; return start; } } var counter = getCounter(1); var startInClosure = eval.call(counter, 'this.start;'); console.log(startInClosure);यह प्रिंट करता है undefinedजबकि मुझे उम्मीद है कि यह 2 होना चाहिए
पाइलीपला

@Pylipala यहाँ प्रश्न दायरे के बाहर के स्थानीय चर का मान न मिलने की संभावना है। यह संभव नहीं है, क्योंकि यह स्थानीय चर की परिभाषा है जो बाहर से सुलभ नहीं होनी चाहिए। अपने कोड के बारे में, आपका मतलब है कि संदर्भ गुंजाइश नहीं है, लेकिन आपने संदर्भ (इस) में शुरुआत नहीं की है , इसलिए आप इसे इस .start के साथ नहीं पढ़ सकते हैं । यहां देखें: paste.ubuntu.com/11560449
iman

@ अपने उत्तर के लिए धन्यवाद। मुझे यह भी लगता है कि यह जावास्क्रिप्ट पक्ष में संभव नहीं है, इसलिए मुझे लगता है कि यह v8 पक्ष में संभव है। मुझे नीचे प्रश्न लिंक मिला जो मेरी समस्या का सटीक वर्णन करता है। इसमें लास रेइकस्टीन कहते हैं, लेकिन माको-टैको हां कहते हैं। मैंने लिंक के रूप में कुछ सी ++ कोड की कोशिश की, लेकिन यह नहीं जानता कि इसे कैसे लिखना है।
पल्लीपाला

32

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

var a = 1, b = 2, c = 3;

for ( var i in window ) {
    console.log(i, typeof window[i], window[i]);
}

कौन से आउटपुट, 150+ अन्य चीजों के बीच , निम्नलिखित हैं:

getInterface function getInterface()
i string i // <- there it is!
c number 3
b number 2
a number 1 // <- and another
_firebug object Object firebug=1.4.5 element=div#_firebugConsole
"Firebug command line does not support '$0'"
"Firebug command line does not support '$1'"
_FirebugCommandLine object Object
hasDuplicate boolean false

इसलिए वर्तमान दायरे में कुछ चर को सूचीबद्ध करना संभव है, लेकिन यह विश्वसनीय, रसीला, कुशल या आसानी से सुलभ नहीं है।

एक बेहतर सवाल यह है कि आप यह जानना चाहते हैं कि चर क्या दायरे में हैं?


2
मुझे लगता है कि प्रश्न अधिक सामान्य था और वेब ब्राउज़र के संदर्भ में जावास्क्रिप्ट तक ही सीमित नहीं था।
राडू सिमियोनेस्कु

यदि आप नोड का उपयोग कर रहे हैं तो "ग्लोबल" के लिए "विंडो" शब्द को बदल दें ... या आप "इस" शब्द का उपयोग कर सकते हैं, लेकिन यह "सख्त का उपयोग करें" के तहत निषिद्ध है
इवान कास्टेलानोस

मैंने hasOwnProperty के लिए एक लाइन जाँच की। उदाहरण के लिए for ( var i in window ) { if (window.hasOwnProperty(i)) { console.log(i, window[i]); }}:। यह कम से कम विरासत में मिली संपत्तियों में कटौती करेगा और आपके चर केवल 50 अन्य गुणों में से होंगे।
तिमित्रन

8
डिबगिंग और / या विकास के उद्देश्यों के लिए किसी को कम से कम यह नहीं देखना चाहिए कि चर क्या दायरे में हैं।
डेक्सिजन

एक और कारण यह जानना चाहता है कि स्थानीय गुंजाइश क्या चर हैं एक बंद को क्रमबद्ध करने के लिए।
माइकल

29

ईसीएमएस्क्रिप्ट 6 में withएक प्रॉक्सी ऑब्जेक्ट के साथ स्टेटमेंट के अंदर कोड को लपेटकर कम या ज्यादा संभव है । ध्यान दें कि इसके लिए गैर-सख्त मोड की आवश्यकता है और यह खराब अभ्यास है।

function storeVars(target) {
  return new Proxy(target, {
    has(target, prop) { return true; },
    get(target, prop) { return (prop in target ? target : window)[prop]; }
  });
}
var vars = {}; // Outer variable, not stored.
with(storeVars(vars)) {
  var a = 1;   // Stored in vars
  var b = 2;   // Stored in vars
  (function() {
    var c = 3; // Inner variable, not stored.
  })();
}
console.log(vars);

प्रॉक्सी के अंदर संदर्भित सभी पहचानकर्ताओं का दावा है with, इसलिए चर असाइनमेंट को लक्ष्य में संग्रहीत किया जाता है। लुकअप के लिए, प्रॉक्सी प्रॉक्सी लक्ष्य या वैश्विक ऑब्जेक्ट (पैरेंट स्कोप नहीं) से मान निकालता है। letऔर constचर शामिल नहीं हैं।

बर्गी के इस जवाब से प्रेरित होकर ।


1
इस तरह की एक सरल तकनीक के लिए यह आश्चर्यजनक रूप से सफल है।
जोनाथन यूनिस

वाह सुपर पावर
पेरी मिमोन

16

आप नहीं कर सकते।

चर, फ़ंक्शन घोषणाओं और फ़ंक्शन कोड के लिए तर्कों के पहचानकर्ता, परिवर्तनीय वस्तु के गुणों के रूप में बाध्य हैं , जो कि प्रशंसनीय नहीं है।

यह सभी देखें:


1
सही है, लेकिन इन-स्कोप वैरिएबल सिर्फ वर्तमान वैरिएबल ऑब्जेक्ट से परे हैं। इन-स्कोप वैरिएबल को स्कोप चेन द्वारा निर्धारित किया जाता है , जो कि वैरिएबल ऑब्जेक्ट्स की एक श्रंखला (सामान्य मामले में) एक चेन है और ग्लोबल ऑब्जेक्ट के साथ समाप्त होती है (हालांकि withस्टेटमेंट को चेन में अन्य ऑब्जेक्ट्स को डालने के लिए इस्तेमाल किया जा सकता है)।
टीजे क्राउडर

Bclary.com के लिंक के लिए +1। ECMA वेबसाइट पर अगले कुछ महीनों में अप-टू-डेट कल्पना का एक HTML संस्करण दिखाई देगा, मुझे यह कहते हुए खुशी हो रही है।
टीजे क्राउडर

3
बस एक नोट, दोनों लिंक टूट गए हैं।
0xc0de सेप

आप कर सकते हैं - स्थैतिक विश्लेषण jsfiddle.net/mathheadinclouds/bvx1hpfn/11 के साथ
mathheadinclouds

8

विशेष रूप से स्कार में प्रवेश पाने के लिए सबसे सरल तरीका

  1. डेवलपर उपकरण खोलें> संसाधन (Chrome में)
  2. उस फ़ंक्शन के साथ फ़ाइल खोलें जिसमें फ़ाइल ढूंढने के लिए उस स्कोप (टिप cmd / ctrl + p) तक पहुँच हो:
  3. उस फ़ंक्शन के अंदर ब्रेकपॉइंट सेट करें और अपना कोड चलाएं
  4. जब यह आपके ब्रेकपॉइंट पर रुक जाता है, तो आप स्कोप (या स्कोप वर्जन विंडो) के माध्यम से स्कोप वर्जन को एक्सेस कर सकते हैं।

नोट: आप इसे अन-मिनिफ़ाइड js के विरुद्ध करना चाहते हैं।

सभी गैर-निजी Vars दिखाने का सबसे सरल तरीका

  1. कंसोल खोलें (Chrome में)
  2. प्रकार: इस
  3. मारो मारो

अब आप एक ऑब्जेक्ट ट्री देखेंगे जिसे आप सभी घोषित वस्तुओं के साथ विस्तारित कर सकते हैं।


7

जैसा कि सभी ने देखा: आप नहीं कर सकते। लेकिन आप एक obj बना सकते हैं और हर उस वर्जन को असाइन कर सकते हैं जो आप उस obj को घोषित करते हैं। इस तरह से आप आसानी से अपने vars देख सकते हैं:

var v = {}; //put everything here

var f = function(a, b){//do something
}; v.f = f; //make's easy to debug
var a = [1,2,3];
v.a = a;
var x = 'x';
v.x = x;  //so on...

console.log(v); //it's all there

1
+1 उदाहरण के लिए शांत उदाहरण, इसे पूरा करने के लिए केवल console.log(window); jsfiddle.net/4x3Tx के
Stano

5

मैं एक बनाया बेला ईमान द्वारा उल्लिखित विचारों से ऊपर लागू करने (अनिवार्य रूप से)। जब आप दूसरे ipsum पर माउस ले जाते हैं तो यह कैसा दिखता हैreturn ipsum*ipsum - ...

यहां छवि विवरण दर्ज करें

जो चर दायरे में हैं, उन्हें हाइलाइट किया जाता है जहां उन्हें घोषित किया जाता है (अलग-अलग स्कोप के लिए अलग-अलग रंगों के साथ)। loremलाल बॉर्डर के साथ एक छाया चर रहा है (नहीं दायरे में है, लेकिन दायरे में हो आगे पेड़ अन्य lorem वहाँ नहीं होगा है।)

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

यह काम किस प्रकार करता है

ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});

अमूर्त वाक्यविन्यास पेड़ बनाता है। फिर,

analysis = escope.analyze(ast);

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

तो सही उत्तर वास्तव में "नहीं" नहीं है, लेकिन "हां, लेकिन" है। "लेकिन" एक बड़ा होना: आपको मूल रूप से जावास्क्रिप्ट में क्रोम ब्राउज़र के महत्वपूर्ण भागों (और यह devtools) को फिर से लिखना होगा। जावास्क्रिप्ट एक ट्यूरिंग पूरी भाषा है, इसलिए निश्चित रूप से यह सिद्धांत रूप में संभव है। जो असंभव है वह आपके स्रोत कोड (एक स्ट्रिंग के रूप में) की संपूर्णता का उपयोग किए बिना पूरी तरह से कर रहा है और फिर उसके साथ अत्यधिक जटिल सामान कर रहा है।


3

यदि आप डिबग की मदद करने के लिए मैन्युअल रूप से चर का निरीक्षण करना चाहते हैं, तो बस डिबगर को फायर करें:

debugger;

सीधे ब्राउज़र कंसोल में।

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