CoffeeScriptでグローバル変数を定義するにはどうすればよいですか?


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);

node.jsでcoffee-scriptを介してコンパイルすると、次のようにラップされます。

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

ドキュメントは言う:

他のスクリプトで使用するトップレベルの変数を作成する場合は、ウィンドウまたはCommonJSのエクスポートオブジェクトのプロパティとしてそれらをアタッチします。CommonJSとブラウザーの両方を対象としている場合、存在演算子(以下で説明)を使用すると、それらを追加する場所を見つける信頼できる方法が得られます。root = exports?この

次に、CoffeeScriptでグローバル変数を定義する方法を教えてください。「ウィンドウのプロパティとして添付する」とはどういう意味ですか?


4
グローバル変数の使用は悪いことに注意してください、c2.com/cgi/wiki?GlobalVariablesAreBad、さらには有害であると考えられているc2.com/cgi/wiki?GotoConsideredHarmful。また、グローバル変数を使用して解決しているほとんどの問題を解決できるクロージャーなどの優れた機能があるため、JavaScriptでこれらを使用する理由はまったくありません。
エフゲニー2011年

9
@Evgenyここで同意しますが、場合によっては、中央の「アプリ」オブジェクトを作成し、それにモジュールをアタッチする必要があります。
jackyalcine

1
中央オブジェクトは、windowオブジェクトやオブジェクトなどの既存のグローバル状態オブジェクトに保存できexportsます。グローバル変数を作成する必要はありません。
エフゲニー

9
@Evgenyグローバル変数はwindow(またはglobalnodejsの)オブジェクトのプロパティとして保存されます
shesek

21
ええ、グローバル変数を持つことはインスタに悪いことではありません。不注意にアプリをホースダウンするのは悪い習慣です。1つを宣言し、それをjQueryのようなアダプタファクトリまたはなんらかの名前空間として使用することは、非常に一般的な方法です。
Erik Reppen 2013

回答:


419

coffeeスクリプトにはvarステートメントがないため、coffeeスクリプトのすべての変数に自動的に挿入されます。これにより、コンパイルされたJavaScriptバージョンがすべてをグローバル名前空間にリークするのを防ぎます

したがって、意図的に物事のコーヒースクリプト側から何かをグローバル名前空間に「漏らす」方法はないため、グローバル変数をグローバルオブジェクトのプロパティとして定義する必要があります

ウィンドウのプロパティとして添付する

これはwindow.foo = 'baz';グローバルオブジェクトがであるため、ブラウザーのケースを処理するのようなものを実行する必要があることを意味しますwindow

Node.js

Node.jsにはwindowオブジェクトはなく、代わりにexportsNode.jsモジュールをラップするラッパーに渡されるオブジェクトがあります(https://github.com/ry/node/blob/master/src/node.js#を参照)。L321)、Node.jsでは、次のようにする必要がありますexports.foo = 'baz';

ここで、ドキュメントからの引用に記載されている内容を見てみましょう。

... CommonJSとブラウザの両方をターゲットにする:root = exports?この

これは明らかにコーヒースクリプトなので、これが実際にコンパイルされる内容を見てみましょう。

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

exportsJavaScriptで存在しない変数を参照しようとすると、そうでなければSyntaxErrorが生成されるため、最初にそれが定義されているかどうかをチェックします(それがで使用される場合を除くtypeof

したがって、exports存在する場合、Node.js(または不適切に記述されたWebサイト...)のexports場合、ルートはを指し、それ以外の場合はを指しthisます。だから何thisですか?

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

.call関数で使用すると、関数のthis内部が最初に渡されたパラメータにバインドされます。ブラウザの場合はオブジェクトにthisなり、windowNode.jsの場合はオブジェクトとしても使用できるグローバルコンテキストになりglobalます。

ただし、requireNode.jsに関数があるので、Node.jsのglobalオブジェクトに何かを割り当てる必要はありません。代わりにexportsrequire関数によって返されるオブジェクトに割り当てます。

コーヒースクリプト

そのすべての説明の後、ここにあなたがする必要があるものがあります:

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

これfooにより、グローバル名前空間で関数が宣言されます(それが何であれ)。
それで全部です :)


1
@IvoWetzel -の違いは何だglobalGLOBALrootNode.jsの中のオブジェクトは?
Aadit M Shah

1
JavaScriptで実在しない変数を参照しようとすると、そうでない場合にSyntaxErrorもたらすであろうあなたが意味するものではありませんがReferenceError
アレックス

12
またはさらに短い:(exports ? this).foo = -> 'Hello World'
Dane O'Connor

3
this.fooは多くの場合!= window.fooですが、「this」コンテキストの場合、コンテキストはすでにオブジェクトです。これは紛らわしい構文です。
ケビン、

1
使用に同意する間global = exports ? this。「Node.jsの場合はグローバルコンテキストになる」という主張は誤りです。これは、this変数が必要な場合、またはnode.jsによって実行される場合、モジュールスコープとして評価されるためです。したがって、小道具を設定すると、グローバルにアクセスできるようになる場合は、がっかりします。場合あなたはNode.jsのコンテキストでグローバルセットのものにしたいですか、あなたは使用する必要があるglobalのではなく、変数をthis
KFL 2014

58

私には@atomiculesが最も単純な答えを持っているようですが、もう少し単純化できると思います。@グローバルにしたいものの前にbefore を置く必要があります。これにより、グローバルオブジェクトにコンパイルされthis.anythingthis参照されます。

そう...

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

bawbag(5, 10)

コンパイルする...

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

そして、node.jsによって与えられたラッパーの内側と外側で動作します

(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以降はグローバルオブジェクトを参照しないため
Sherwin Yu

1
これは正しいので、変数を適切なスコープで定義して(および他のスコープで使用して)、window.myVariableどこで機能するかを定義できます。
ビリームーン

2
this / global名前空間で関数を作成するようにcoffeescriptに指示する=>代わりに、別の変数を定義する必要はありません->
Ricardo Villamil

2
これはとても役に立ったので、別のコーヒースクリプトでグローバルオブジェクトと関数を作成できるようになりました
Diego Fernando Murillo Valenci '31年

これはずっと良いです。JSをCSに転送するには、ウィンドウオブジェクトを使用するように多くの関数呼び出しを変更する必要がありました。これを元に戻すことができます
casraf

33

Ivoはそれを釘付けにしましたが、使用できるダーティトリックが1つあることをお伝えしますが、スタイルポイントを使用する場合はお勧めしません。バッククォートでエスケープすることにより、JavaScriptコードをCoffeeScriptに直接埋め込むことができます。

ただし、これが通常悪い考えである理由は次のとおりです。CoffeeScriptコンパイラーはこれらの変数を認識しません。つまり、CoffeeScriptのスコープ規則に従っていないということです。そう、

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

コンパイルする

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

これで、fooスコープが異なる2つのができました。Ivyが説明したように、グローバルオブジェクトを参照せずにCoffeeScriptコードからグローバル を変更する方法はありませんfoo

もちろん、これはfoo、CoffeeScriptで割り当てを行った場合にのみ問題にfooなります。つまり、初期値(つまり、グローバル定数)が与えられた後に読み取り専用になった場合、埋め込みJavaScriptソリューションのアプローチは、ある程度受け入れられる可能性があります(ただし、推奨されません)。


1
CoffeeScriptでTitaniumを使用しているので、これは私にとって便利なソリューションでした。エクスポートとウィンドウオブジェクトは存在しません。
Pier-Olivier Thibault 2012年

実際にfooは、var巻き上げのためにローカル変数は1つだけです(JSはすべてのvar宣言を先にスキャンして、関数の先頭にあるかのように解釈します)
Kornel

@porneLあなたは正しいです。私は悪い例を選びました。ポイントは、CoffeeScriptコンパイラーがバックティックエスケープされたJavaScriptの分析を実行しないため、奇妙な出力が得られる可能性があるということです。
Trevor Burnham

2
@ Pier-OlivierThibault Titaniumでグローバルを使用する場合は、Ti.App.myGlobalVar = "ImAGlobalVar"を使用できます。バック
ティックは

これは、少なくともNode.jsの正解です。実行expect = require('chai').expect;するとexpect、すべてのテストファイルで変数を使用できるようになります。
pocesar 2013年

11

node.jsの下でcoffee-scriptを介してコードをコンパイルするときに-bオプションを渡すことができます。コンパイルされたコードはcoffeescript.orgと同じになります。


どうやって?-bオプションはどこに置くのですか?
Harry

1
@ハリー- -b/ コマンドの--bare直後に移動しcoffeeます。
ocodo 2014年

9

Ivo Wetzelの回答に追加するには

Googleグループの投稿でexports ? this文書化/言及されたものしか見つけられないための簡略構文があるようですです。

つまり、ウェブページで関数をグローバルに使用できるようにするには、関数を@プレフィックスで再度宣言します。

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

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

9
@aglobalfunctionの「@」は単に「this。」に置き換えられるため、「this.aglobalfunction」にコンパイルされます。これが機能するのは、coffeescriptラッパー関数(適用されている場合)のスコープがグローバルスコープであるためです。
Chris

9

あなたが達成しようとしていることは、このように簡単に行うことができると思います:

coffeescriptをコンパイルしている間、「-b」パラメーターを使用します。

-b/ --bare トップレベルの関数安全ラッパーなしでJavaScriptをコンパイルします。

だからこのようなもの: 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

上記のCoffeeScriptは単ににコンパイルされ(function(){ return this })()ます。そのため、グローバルオブジェクトに確実にアクセスするための動作を実行しています。


これは素晴らしいです!
メタリム

私のために働いた唯一のもの。CoffeeScriptが嫌いです。
pcv 2016

CoffeeScriptが大好きです。これまでのところ、これは最高のプログラミング言語です。それが趣味のプロジェクトとして作成され、維持されているのはあまりにも悪く、その使用パターンに混乱と愚かさをもたらしました。
メタリム

3

コーヒースクリプトはそれ自体で使用されることはめったにないので、あなたは使うことができます global、node.jsまたはbrowserify(およびcoffeeify、gulpビルドスクリプトなどの子孫)によって提供される変数。

node.js内 globalはグローバル名前空間です。

browserify globalは次と等しいwindowです。

これだけ:

somefunc = ->
  global.variable = 123
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.