मैं कॉफ़ीस्क्रिप्ट में वैश्विक चर कैसे परिभाषित करूं?


317

Coffeescript.org पर:

bawbag = (x, y) ->
    z = (x * y)

bawbag(5, 10) 

इसके लिए संकलन करेगा:

var bawbag;
bawbag = function(x, y) {
  var z;
  return (z = (x * y));
};
bawbag(5, 10);

नोड के तहत कॉफ़ी-स्क्रिप्ट के माध्यम से संकलन करना।

(function() {
  var bawbag;
  bawbag = function(x, y) {
    var z;
    return (z = (x * y));
  };
  bawbag(5, 10);
}).call(this);

डॉक्स कहते हैं:

यदि आप अन्य लिपियों के उपयोग के लिए शीर्ष-स्तरीय चर बनाना चाहते हैं, तो उन्हें विंडो पर या कॉमनजस में निर्यात वस्तु के रूप में संलग्न करें। अस्तित्वगत ऑपरेटर (नीचे कवर), आपको यह पता लगाने का एक विश्वसनीय तरीका देता है कि उन्हें कहां जोड़ा जाए, यदि आप दोनों कॉमनजेएस और ब्राउज़र को लक्षित कर रहे हैं: रूट = निर्यात? इस

मैं कैसे कॉफी चर में तो वैश्विक चर को परिभाषित करते हैं। 'उन्हें विंडो पर प्रॉपर्टी के रूप में संलग्न' का क्या मतलब है?


4
ध्यान दें कि वैश्विक चर का उपयोग करना बुरा है, c2.com/cgi/wiki?GlobalVariablesAreBad , और यहां तक ​​कि हानिकारक माना जाता है, c2.com/cgi/wiki?GotoConsideredHarmful । और वास्तव में जावास्क्रिप्ट में इनका उपयोग करने का कोई कारण नहीं है, क्योंकि आपके पास बंद करने जैसी महान विशेषताएं हैं जो अधिकांश समस्याओं को हल कर सकते हैं जिन्हें आप हल करने के लिए वैश्विक चर का उपयोग कर रहे हैं।
एवगेनी

9
@Evgeny जबकि मैं आपसे यहाँ सहमत हूँ, कुछ मामलों में यह एक केंद्रीय 'ऐप' ऑब्जेक्ट बनाने के लिए आवश्यक है और इसमें मॉड्यूल संलग्न हैं।
१२:३२ बजे जैकलिन

1
केंद्रीय वस्तुओं को मौजूदा वैश्विक राज्य वस्तुओं में बचाया जा सकता है, जैसे windowवस्तु या exportsवस्तु। वैश्विक चर बनाने की कोई आवश्यकता नहीं है।
एवगेनी

9
@Evgeny वैश्विक चर को window(या globalनोडज पर) वस्तु के गुणों के रूप में सहेजा जाता है
shesek

21
हाँ, यह वैश्विक संस्करण के लिए इंस्टा-बैड नहीं है। बस उनके साथ अपने ऐप को बिना सोचे समझे खराब करने का अभ्यास करें। एक की घोषणा करना और एक एडॉप्टर फैक्टरी जैसे कि jQuery या किसी प्रकार के नामस्थान का उपयोग करना वास्तव में आम बात है।
एरिक रेपेन

जवाबों:


419

चूंकि कॉफी स्क्रिप्ट का कोई varबयान नहीं है, इसलिए यह स्वचालित रूप से कॉफी-स्क्रिप्ट में सभी चर के लिए सम्मिलित करता है, इस तरह यह संकलित जावास्क्रिप्ट संस्करण को वैश्विक नामस्थान में सब कुछ लीक करने से रोकता है ।

इसलिए , उद्देश्य पर चीजों के कॉफी-स्क्रिप्ट पक्ष से वैश्विक नाम स्थान में कुछ "लीक" करने का कोई तरीका नहीं है , आपको अपने वैश्विक चर को वैश्विक वस्तु के गुणों के रूप में परिभाषित करने की आवश्यकता है ।

उन्हें विंडो पर गुण के रूप में संलग्न करें

इसका मतलब है कि आपको कुछ ऐसा करने की ज़रूरत है window.foo = 'baz';, जो ब्राउज़र केस को हैंडल करता है, क्योंकि ग्लोबल ऑब्जेक्ट है window

Node.js

Node.js में कोई windowवस्तु नहीं है, इसके बजाय वह exportsवस्तु है जो Node.js मॉड्यूल को लपेटने वाले आवरण में पास हो जाती है (देखें: https://github.com/ry/node/blob/master/src/node.js# L321 ), इसलिए Node.js में आपको क्या करने की आवश्यकता है exports.foo = 'baz';

अब हम डॉक्स से आपकी बोली में क्या कहते हैं, इस पर एक नज़र डालते हैं:

... दोनों CommonJS और ब्राउज़र को लक्षित करते हुए: रूट = निर्यात? इस

यह स्पष्ट रूप से कॉफी-स्क्रिप्ट है, तो आइए एक नज़र डालते हैं कि यह वास्तव में क्या संकलन करता है:

var root;
root = (typeof exports !== "undefined" && exports !== null) ? exports : this;

पहले यह जांच करेगा कि क्या exportsपरिभाषित किया गया है, क्योंकि जावास्क्रिप्ट में एक गैर-मौजूद चर को संदर्भित करने की कोशिश कर रहा है अन्यथा एक सिंटैक्सएयर (केवल इसके साथ उपयोग किए जाने पर छोड़कर typeof) प्राप्त होगा

तो अगर exportsमौजूद है, जो कि Node.js (या बुरी तरह से लिखे गए वेबसाइट ...) के मामले में है, तो रूट इंगित करेगा exports, अन्यथा this। तो क्या है this?

(function() {...}).call(this);

.callकिसी फ़ंक्शन पर उपयोग करने thisसे फ़ंक्शन को पहले पैरामीटर में पारित कर दिया जाएगा, जो ब्राउज़र के मामले में thisअब windowऑब्जेक्ट होगा, Node.js के मामले में यह वैश्विक संदर्भ होगा जो globalऑब्जेक्ट के रूप में भी उपलब्ध है ।

लेकिन चूंकि आपके पास requireNode.js में फ़ंक्शन है, इसलिए Node.js में globalऑब्जेक्ट को कुछ असाइन करने की आवश्यकता नहीं है , इसके बजाय आप exportsऑब्जेक्ट को असाइन करते हैं जो तब requireफ़ंक्शन द्वारा वापस आ जाता है।

कॉफी-स्क्रिप्ट

उस सब स्पष्टीकरण के बाद, यहाँ आपको क्या करना है:

root = exports ? this
root.foo = -> 'Hello World'

यह fooवैश्विक नाम स्थान (जो कुछ भी होता है) में हमारे कार्य की घोषणा करेगा ।
बस इतना ही :)


1
@IvoWetzel - बीच क्या अंतर है global, GLOBALऔर rootNode.js में वस्तुओं?
आदित एम शाह

1
जावास्क्रिप्ट में एक गैर-मौजूद चर को संदर्भित करने की कोशिश करना अन्यथा एक सिंटैक्स ईयरर्र उपज होगा क्या आपका मतलब नहीं है ReferenceError?
एलेक्स

12
या उससे भी छोटा:(exports ? this).foo = -> 'Hello World'
डेन ओ'कॉनर

3
if.foo अक्सर है! = window.foo हालांकि अगर आप 'यह' संदर्भ पहले से ही एक वस्तु है। यह एक भ्रामक वाक्यविन्यास है।
केविन

1
जबकि मैं उपयोग करने से सहमत हूं global = exports ? this। यह दावा कि "Node.js के मामले में यह वैश्विक संदर्भ होगा ..." गलत है क्योंकि thisपरिवर्तनीय, जब आवश्यक हो या नोड.जेएस द्वारा चलाया जाता है, का मूल्यांकन मॉड्यूल क्षेत्र के रूप में किया जाता है। इसलिए यदि आप उम्मीद करते हैं कि यह प्रॉप्स की स्थापना को विश्व स्तर पर सुलभ बना देगा, तो आप निराश होंगे। यदि आप नोड.जेएस संदर्भ में विश्व स्तर पर चीजों को सेट करना चाहते हैं, तो आपको globalइसके बजाय चर का उपयोग करने की आवश्यकता है this
KFL

58

मेरे लिए ऐसा लगता है कि @atomicules का सबसे सरल उत्तर है, लेकिन मुझे लगता है कि इसे थोड़ा और सरल बनाया जा सकता है। आपको @वैश्विक होने के लिए कुछ भी करने से पहले एक चीज रखने की जरूरत है , ताकि वह वैश्विक वस्तु को संकलित this.anythingऔर thisसंदर्भित करे।

इसलिए...

@bawbag = (x, y) ->
    z = (x * y)

bawbag(5, 10)

के लिए संकलन ...

this.bawbag = function(x, y) {
  var z;
  return z = x * y;
};
bawbag(5, 10);

और नोड के द्वारा दिए गए आवरण के अंदर और बाहर काम करता है

(function() {
    this.bawbag = function(x, y) {
      var z;
      return z = x * y;
    };
    console.log(bawbag(5,13)) // works here
}).call(this);

console.log(bawbag(5,11)) // works here

7
लेकिन यह काम नहीं करेगा यदि आप पहले से ही किसी अन्य दायरे के अंदर हैं? क्योंकि तब thisकोई वैश्विक वस्तु
शेरविन यू

1
यह सही है, इसलिए आप या तो अपने चर को एक उपयुक्त दायरे में परिभाषित कर सकते हैं (और दूसरों में इसका उपयोग कर सकते हैं), या इसे परिभाषित करें window.myVariableजो कहीं भी काम करेगा।
बिली मून

2
आपको =>इसके बजाय एक अन्य चर को परिभाषित करने की आवश्यकता नहीं है ->जो इस / वैश्विक नाम स्थान के तहत फ़ंक्शन बनाने के लिए कॉफ़ीस्क्रिप्ट का निर्देश देता है
रिकार्डो विल्मिल

2
यह इतना मददगार था, अब मैं एक अलग कॉफी स्क्रिप्ट में वैश्विक वस्तुओं और कार्यों का निर्माण कर सकता हूं
डिएगो फर्नांडो मुरिलो वालेंकी

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

33

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

हालांकि, यहाँ यह आमतौर पर एक बुरा विचार क्यों है: कॉफीस्क्रिप्ट कंपाइलर उन चर से अनजान है, जिसका अर्थ है कि वे सामान्य कॉफीस्क्रिप्ट स्कूपिंग नियमों का पालन नहीं करेंगे। इसलिए,

`foo = 'bar'`
foo = 'something else'

के लिए संकलित करता है

foo = 'bar';
var foo = 'something else';

और अब आप अपने आप fooको अलग-अलग स्कोप में दो एस कर चुके हैं वैश्विक वस्तु को संदर्भित किए बिना कॉफीस्क्रिप्ट कोड से वैश्विक को संशोधित करने का कोई तरीका नहीं है foo, जैसा कि आईवी ने वर्णित किया है।

बेशक, यह केवल एक समस्या है यदि आप fooCoffeeScript में असाइनमेंट करते हैं - यदि fooकेवल इसका प्रारंभिक मूल्य (यानी यह एक वैश्विक स्थिर है) दिए जाने के बाद ही पढ़ा गया है, तो एम्बेडेड जावास्क्रिप्ट समाधान दृष्टिकोण थोड़े सॉर्टा स्वीकार्य हो सकता है (हालांकि अभी भी सिफारिश नहीं की गई)।


1
यह मेरे लिए एक उपयोगी समाधान था क्योंकि मैं CoffeeScript के साथ टाइटेनियम का उपयोग कर रहा हूं। निर्यात और विंडो ऑब्जेक्ट वहां मौजूद नहीं हैं।
पियर-ओलिवियर थिबॉल्ट

वास्तव में यह सिर्फ एक स्थानीय fooपरिवर्तन है, क्योंकि varफहराने (जेएस सभी varघोषणाओं के लिए आगे स्कैन करता है और उनकी व्याख्या करता है जैसे कि वे समारोह में सबसे ऊपर थे)
कोर्नेल

@ चोंचले तुम सही हो; मैंने एक बुरी मिसाल उठाई। मुद्दा यह है कि CoffeeScript कंपाइलर backtick-escaped JavaScript का कोई विश्लेषण नहीं करता है, जिससे आप विषम आउटपुट प्राप्त कर सकते हैं।
ट्रेवर बर्नहैम

2
@ पियर-ओलिविएरिबाल्ट यदि आप टाइटेनियम में ग्लोबल्स का उपयोग करना चाहते हैं, तो आप Ti.App.myGlobalVar = "ImAGlobalVar" का उपयोग कर सकते हैं और बैकटिक्स की आवश्यकता नहीं है
जैकब लेनर

यह सही उत्तर है, कम से कम Node.js के लिए। कर expect = require('chai').expect;बनाता है expectचर मेरे सारे परीक्षण फाइलों में उपलब्ध है!
पोकेसर

11

जब आप नोड-कॉफी के तहत कॉफी-स्क्रिप्ट के माध्यम से कोड संकलित करते हैं तो आप बी विकल्प को पास कर सकते हैं। संकलित कोड coffeescript.org पर ही होगा।


कैसे? मैं -b विकल्प कहां रखूं?
हैरी

1
@Harry - -b/ कमांड के --bareबाद सीधे जाता है coffee
ओसोडो

9

इवो ​​वेटजेल के जवाब में जोड़ने के लिए

ऐसा लगता है exports ? thisकि मैं केवल एक Google समूह पोस्टिंग पर प्रलेखित / उल्लिखित पाया जा सकता है, इसके लिए एक शॉर्टहैंड सिंटैक्स लगता है ।

एक वेब पेज में Ie एक फ़ंक्शन को उपलब्ध कराने के लिए विश्व स्तर पर आप फ़ंक्शन को फिर से @उपसर्ग के साथ घोषित करते हैं :

<script type="text/coffeescript">
    @aglobalfunction = aglobalfunction = () ->
         alert "Hello!"
</script>

<a href="javascript:aglobalfunction()" >Click me!</a>

9
@Aglobalfunction में '@' को केवल 'इस' से बदल दिया जाता है, इसलिए 'this.aglobalfunction' को संकलित किया जाता है। यह काम करता है क्योंकि कॉफ़ीस्क्रिप्ट रैपर फ़ंक्शन (यदि लागू हो) का दायरा वैश्विक गुंजाइश है।
क्रिस

9

मुझे लगता है कि आप जो हासिल करने की कोशिश कर रहे हैं वह बस इस तरह किया जा सकता है:

जब आप कॉफ़ीस्क्रिप्ट को संकलित कर रहे हैं, तो "-b" पैरामीटर का उपयोग करें।

-b/ --bare शीर्ष-स्तरीय फ़ंक्शन सुरक्षा आवरण के बिना जावास्क्रिप्ट संकलित करें।

तो कुछ इस तरह: coffee -b --compile somefile.coffee whatever.js

यह आपके कोड को CoffeeScript.org साइट की तरह ही आउटपुट करेगा।


7

यदि आप एक बुरे व्यक्ति हैं (मैं एक बुरा व्यक्ति हूं।), तो आप इस तरह से सरल हो सकते हैं: (->@)()

जैसे की,

(->@)().im_a_terrible_programmer = yes
console.log im_a_terrible_programmer

यह काम करता है, क्योंकि जब एक लागू Referenceएक करने के लिए Function'नंगे' (यह है कि, func()के बजाय new func()या obj.func()), कुछ आमतौर पर करने के लिए 'समारोह-कॉल मंगलाचरण पैटर्न', के रूप में संदर्भित हमेशा बांधता thisहै कि वैश्विक स्तर पर वस्तु के लिए निष्पादन संदर्भ

ऊपर दिए गए कॉफीस्क्रिप्ट बस के लिए संकलित करते हैं (function(){ return this })(); इसलिए हम वैश्विक वस्तु तक पहुंच बनाने के लिए उस व्यवहार का उपयोग कर रहे हैं।


ये जबरदस्त है!
मेटलिम

केवल एक चीज जो मेरे लिए काम करती है। कॉफी से नफरत है।
पीसीवी

कॉफी के शौकीन। अब तक यह सबसे अच्छी प्रोग्रामिंग भाषा है। बहुत बुरा यह एक शौक परियोजना के रूप में बनाया और बनाए रखा गया था, इसके उपयोग के पैटर्न में अराजकता और मूर्खता के लिए अग्रणी था।
मेटलिम

3

चूंकि कॉफ़ीस्क्रिप्ट का उपयोग शायद ही कभी किया जाता है, इसलिए आप globalनोड द्वारा आपूर्ति किए गए वेरिएबल का उपयोग कर सकते हैं। जेएस या ब्राउज़राइज़ करें (और किसी भी वंशज जैसे कॉफ़ी, ग्लुप बिल्ड स्क्रिप्ट आदि)।

नोड.जेएस globalमें वैश्विक नामस्थान है।

ब्राउज़र globalमें के बराबर है window

बस ऐसे:

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