Как определить глобальные переменные в 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, который вы можете использовать внутри функции.