Coffeescript est un langage compilé en javascript. Il n’est pas interprété nativement, il doit d’abord être converti en javascript afin d’être utilisable.
Il est à noter que coffeescript sera inclus directement dans rails 3.1.
Quelques arguments avant de rentrer dans le vif du sujet:
En coffee, vous n’avez pas besoin d’utiliser explicitement le mot clé var, ni les «;», ceux ci seront générés automatiquement pour vous.
1 is 1
# true
1 is "1"
# false
or= est l’équivalent de | = |
Attention avec a or= b
a prendra la valeur de b si a est null, undefined, false, vaut 0 ou “” qui valent tous false une fois convertis en booléen.
a ?= b affectera la valeur de b dans a uniquement si a est null ou undefined.
Il s’agit en fait d’un raccourci syntaxique. Chaque valeur définie peut être testée avec ?
a = null
a?
=> false
b = 42
b?
=> true
Equivalences de notation:
# équivalences
a ?= b
a = b unless a?
a = a ? b
A chaque fois que vous voyez -> il s’agit en fait d’une définition de fonction. C’est un concept central dans coffeescript.
Définissions notre première fonction anonyme:
() -> console.log "Hello from coffee"
donnera en js:
(function() {
return console.log("Hello from coffee");
});
Si vous avez besoin de pouvoir rappeler votre fonction, ce qui sera souvent le cas, excepté pour les callbacks, il vous suffit de l’affecter:
cube = (num) -> Math.pow num, 3
donnera en js:
cube = function(num) {
return Math.pow(num, 3);
};
Je ne vous montre qu’une partie du code généré mais le compilateur généré aussi les déclarations de variable pour vous et enrobe le tout dans une fonction anonyme (voir portée).
Nous avons vu comment passer un argument et nommer une fonction.
Important: la génération des fonctions se fait de la forme suivante:
var f = function() {}
// et non:
function f() {}
Les deux syntaxes sont complètement valides, mais c’est la première qui a été retenue pour des raisons de compatibilité avec IE.
Toutefois celle ci est plus contraignante car vous ne pouvez appeler une fonction que quand elle a été définie.
L’ordre de définition est donc très important.
Les fonctions offrent la prise en charge des arguments par défaut.
helloWorld = (street = "Lille") -> console.log "Hello world from #{street}."
helloWorld()
# Hello world from Lille.
helloWorld("Paris")
# Hello world from Paris.
Les splat permettent de définir un nombre variable d’arguments qui seront récupérés comme un tableau:
f = (a, b..., c) ->
f("a", "foo", "bar", "baz", 42)
# b => [ 'foo', 'bar', 'baz' ]
A noter que les arguments hors splat sont les premiers à être assignés:
f("a", 42)
b # []
Les splats peuvent être utilisés hors fonction:
[a..., b] = ["foo", "bar", 42]
a # [ 'foo', 'bar' ]
Le moindre code coffeescript est transformé en un code javascript enrobé dans une fonction anonyme.
Cela présente un avantage et un inconvénient. D’une part vous ne risquez pas de rencontrer des conflits de nom ou de portée car le code générée ne peut pas écraser un code existant (namespacing).
D’autre part cela peut poser des problèmes si deux fichiers ont besoin d’interagir.
Au niveau compilation il est possible d’éviter cela avec l’option –no-wrap.
Au niveau code il est possible d’utiliser l’objet global window pour affecter les différents modules.
Par exemple pour déclarer une classe utilisable depuis un autre morceau de code coffee:
window.App = class App
Il est facile de s’arracher les cheveux si on maitrise mal la portée en javascript. Posez vous toujours la question: qui est this dans ce contexte ?
Coffeescript vous offre un raccourci syntaxe pour accèder directement à la propriété d’un objet:
@attribute équivaut à this.attribute
C’est pratique, notamment pour les classes (voir partie Les classes), mais aussi pour tout objet.
person = { firstname: "Martin", lastname: "Catty" }
person.introduce = -> console.log "Bonjour, je suis #{@firstname} #{@lastname}."
person.introduce()
# Bonjour, je suis Martin Catty.
Cette syntaxe vient avec un raccourci syntaxique. Par exemple dans le cas classique de définition d’un setter.
setAttribute = (attribute) -> @attribute = attribute
peut être raccourci en:
setAttribute = (@attribute) ->
Coffeescript offre un mécanisme extrèmement simple pour garantir le this actuel. Plutôt que de définir votre fonction avec -> il suffit d’utiliser =>
Exemple:
registerEvents = (node) ->
node.bind "click", (event) =>
Coffeescript introduit un mécanisme de classe très puissant:
window.Animal = class Animal
window.Dog = class Dog extends Animal
# convention pour une constante mais utilise var
STATES = ["sleeping", "eating"]
constructor: ->
# appelle le constructeur d'Animal
super
# méthode de l'objet
speak: ->
console.log "woff."
# variable de classe
@count: 0
# méthode statique
@incCount: -> @count++
La convention est de stocker ses fichiers dans app/coffeescripts/
Ensuite il s’agit de générer les fichiers correspondant. Pour cela guard fait très bien l’affaire.
# Gemfile:
group :development do
gem 'guard'
gem 'guard-coffeescript'
end
# Guardfile
group 'frontend' do
guard 'coffeescript', :output => 'public/javascripts/compiled' do
watch(%r{^app/coffeescripts/.+\.coffee$})
end
end
bundle exec guard
Il est possible d’appeler du js depuis du coffee avec les backticks `.
L’apprentissage de coffeescript est assez simple, surtout si vous utilisez actuellement ruby et que vous avez une bonne base en javascript.
Le temps d’apprentissage me semble largement valoir le gain en temps de développement et maintenance.
Bref, l’essayer c’est l’adopter.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.