Как определить глобальные переменные в CoffeeScript?

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

компиляция с помощью coffee-script под node.js оборачивает это так:

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

Документы говорят:

Если вы хотите создать переменные верхнего уровня для использования другими сценариями, прикрепите их как свойства к окну или к объекту экспорта в CommonJS. Экзистенциальный оператор (описанный ниже) дает вам надежный способ выяснить, куда их добавить, если вы ориентируетесь и на CommonJS, и на браузер: root = exports? этот

Как определить глобальные переменные тогда в CoffeeScript. Что означает "прикрепить их как свойства к окну"?

9 ответов

Решение

Так как кофейного сценария нет var оператор автоматически вставляет его для всех переменных в coffee-script, таким образом предотвращая утечку скомпилированной версии JavaScript в глобальное пространство имен.

Таким образом, поскольку нет никакого способа сделать что-то "просачивающимся" в глобальное пространство имен со стороны кофейных сценариев, вы должны определить свои глобальные переменные как свойства глобального объекта.

прикрепить их как свойства на окне

Это означает, что вам нужно сделать что-то вроде 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, так и на браузер: root = export? этот

Это, очевидно, Coffee-скрипт, так что давайте посмотрим, к чему это на самом деле компилируется:

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

Сначала он проверит, exports определяется, поскольку попытка сослаться на несуществующую переменную в JavaScript в противном случае приведет к ошибке SyntaxError (кроме случаев, когда она используется с typeof)

Так что если exports существует, что имеет место в Node.js (или в плохо написанном веб-сайте...) корень будет указывать на exportsиначе this, И что this?

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

С помощью .call на функции будет связывать this внутри функции передается первый параметр, в случае браузера this теперь будет window объект, в случае Node.js это будет глобальный контекст, который также доступен как global объект.

Но так как у вас есть require функция в Node.js, нет необходимости назначать что-то global объект в Node.js, вместо этого вы назначаете exports объект, который затем возвращается require функция.

Кофе-Script

После всего этого объяснения вот что вам нужно сделать:

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

Это объявит нашу функцию foo в глобальном пространстве имен (что бы это ни было).
Это все:)

Мне кажется, @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);

и работает внутри и снаружи оболочки, предоставленной 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

Ivo прибил его, но я упомяну, что есть один грязный трюк, который вы можете использовать, хотя я не рекомендую его, если вы собираетесь использовать стилевые точки: вы можете встраивать код JavaScript прямо в ваш CoffeeScript, избегая его с помощью обратных символов.

Однако, вот почему это обычно плохая идея: компилятор CoffeeScript не знает об этих переменных, что означает, что они не будут подчиняться нормальным правилам области действия CoffeeScript. Так,

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

компилируется в

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

и теперь у вас есть два fooв разных сферах. Там нет никакого способа изменить глобальный foo из кода CoffeeScript без ссылки на глобальный объект, как описано Айви.

Конечно, это только проблема, если вы делаете назначение foo в CoffeeScript - если foo стал доступным только для чтения после того, как ему было присвоено его начальное значение (т. е. это глобальная константа), тогда подход к встроенному решению JavaScript может быть своего рода приемлемым (хотя все еще не рекомендуется).

Вы можете передать опцию -b, когда компилируете код с помощью coffee-script в файле node.js. Скомпилированный код будет таким же, как на coffeescript.org.

Я думаю, что вы пытаетесь достичь, можно просто сделать так:

Пока вы компилируете coffeescript, используйте параметр "-b".

-b / --bare Скомпилируйте JavaScript без функции-оболочки безопасности верхнего уровня.

Так что-то вроде этого: coffee -b --compile somefile.coffee whatever.js

Это выведет ваш код так же, как на сайте CoffeeScript.org.

Добавить к ответу Иво Ветцеля

Там, кажется, сокращенный синтаксис для exports ? this что я могу найти только документированные / упомянутые в публикации группы Google.

То есть на веб-странице, чтобы сделать функцию доступной глобально, вы объявляете функцию снова с @ префикс:

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

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

Если вы плохой человек (я плохой человек), вы можете получить так просто: (->@)()

Как в,

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

Это работает, потому что при вызове Reference к Function "голый" (то есть func(), вместо new func() или же obj.func()), то, что обычно называют "шаблоном вызова вызова функции", всегда связывает this к глобальному объекту для этого контекста выполнения.

Приведенный выше CoffeeScript просто компилируется в (function(){ return this })(); поэтому мы используем это поведение для надежного доступа к глобальному объекту.

Поскольку coffeescript редко используется сам по себе, вы можете использовать global переменная, предоставляемая либо node.js, либо browserify (и любыми потомками, такими как coffeeify, сценарии сборки gulp и т. д.).

В node.js global это глобальное пространство имен.

В браузере global равно window,

Итак, просто:

somefunc = ->
  global.variable = 123

Лично я думаю, что вы слишком сосредоточены на том, что в CoffeeScript нельзя сказать:

      let x

в вашем основном коде. Но ничто не мешает вам сказать:

      x = undefined

в вашем основном коде, который создаст переменную x. Я хотел быть уверенным, что когда вы позже будете ссылаться (или назначать) x внутри функции, она будет использовать тот же самый x, поэтому я написал этот скрипт:

      x = undefined

func = () ->
    console.log "x = #{x}"
    x = 5
    console.log "x = #{x}"

func()
console.log "x = #{x}"

который выводит:

      x = undefined
x = 5
x = 5

поэтому есть только один x, который вы можете использовать внутри функции.

Другие вопросы по тегам