LiveScript est un langage qui se compile en JavaScript. Il a un rapport direct avec JavaScript, et vous permet d'écrire du JavaScript de façon considérables sans répétitivité. LiveScript ajoute non seulement des fonctionnalités pour écrire du code fonctionnel, mais possède aussi nombre d'améliorations pour la programmation orientée objet et la programmation impérative.
LiveScript est un descendant indirect de CoffeeScript, direct de Coco avec beaucoup plus de compatibilité.
Suivez @gkzahariev (EN) pour vous tenir au courant.
Dernier article: Powerful jQuery with LiveScript (EN)
Double-cliquez un exemple pour le compiler.
Fonction currifiée, switch implicite, opérateur de concaténation, et composition de fonctions :
take = (n, [x, ...xs]:list) --> | n <= 0 => [] | empty list => [] | otherwise => [x] ++ take n - 1, xs take 2, [1 2 3 4 5] #=> [1, 2] take-three = take 3 take-three [3 to 8] #=> [3, 4, 5] # Composition, 'reverse' de prelude.ls last-three = reverse >> take-three >> reverse last-three [1 to 8] #=> [6, 7, 8]
var take, takeThree, lastThree, slice$ = [].slice; take = curry$(function(n, list){ var x, xs; x = list[0], xs = slice$.call(list, 1); switch (false) { case !(n <= 0): return []; case !empty(list): return []; default: return [x].concat(take(n - 1, xs)); } }); take(2, [1, 2, 3, 4, 5]); takeThree = take(3); takeThree([3, 4, 5, 6, 7, 8]); lastThree = compose$(reverse, takeThree, reverse); lastThree([1, 2, 3, 4, 5, 6, 7, 8]); function curry$(f, bound){ var context, _curry = function(args) { return f.length > 1 ? function(){ var params = args ? args.concat() : []; context = bound ? context || this : this; return params.push.apply(params, arguments) < f.length && arguments.length ? _curry.call(context, params) : f.apply(context, params); } : f; }; return _curry(); } function compose$() { var functions = arguments; return function() { var i, result; result = functions[0].apply(this, arguments); for (i = 1; i < functions.length; ++i) { result = functions[i](result); } return result; }; }
# Listage facile, objets implicites table1 = * id: 1 name: 'george' * id: 2 name: 'mike' * id: 3 name: 'donald' table2 = * id: 2 age: 21 * id: 1 age: 20 * id: 3 age: 26 # Accès implicite, accessignment up-case-name = (.name .= to-upper-case!) # Compréhensions, déstructuration, piping [{id:id1, name, age} for {id:id1, name} in table1 for {id:id2, age} in table2 when id1 is id2] |> sort-by (.id) # 'sort-by' de prelude.ls |> each up-case-name # 'each' de prelude.ls |> JSON.stringify #=> #[{"id":1,"name":"GEORGE","age":20}, # {"id":2,"name":"MIKE", "age":21}, # {"id":3,"name":"DONALD","age":26}] # Opérateurs en tant que fonctions, pipe inversée map (.age), table2 |> fold1 (+) #=> 67 ('fold1' et 'map' de prelude.ls)
var table1, table2, upCaseName, id1, name, id2, age; table1 = [ { id: 1, name: 'george' }, { id: 2, name: 'mike' }, { id: 3, name: 'donald' } ]; table2 = [ { id: 2, age: 21 }, { id: 1, age: 20 }, { id: 3, age: 26 } ]; upCaseName = function(it){ return it.name = it.name.toUpperCase(); }; JSON.stringify( each(upCaseName)( sortBy(function(it){ return it.id; })( (function(){ var i$, ref$, len$, ref1$, j$, len1$, ref2$, results$ = []; for (i$ = 0, len$ = (ref$ = table1).length; i$ < len$; ++i$) { ref1$ = ref$[i$], id1 = ref1$.id, name = ref1$.name; for (j$ = 0, len1$ = (ref1$ = table2).length; j$ < len1$; ++j$) { ref2$ = ref1$[j$], id2 = ref2$.id, age = ref2$.age; if (id1 === id2) { results$.push({ id: id1, name: name, age: age }); } } } return results$; }())))); fold1(curry$(function(x$, y$){ return x$ + y$; }))( map(function(it){ return it.age; }, table2)); function curry$(f, bound){ var context, _curry = function(args) { return f.length > 1 ? function(){ var params = args ? args.concat() : []; context = bound ? context || this : this; return params.push.apply(params, arguments) < f.length && arguments.length ? _curry.call(context, params) : f.apply(context, params); } : f; }; return _curry(); }
Rappels désimbriqués (backcalls) , chaînage sans parenthèses :
<- $ 'h1' .on 'click' alert 'boom!'
$('h1').on('click', function(){ return alert('boom!'); });
Vous pouvez installer LiveScript depuis Node Package Manager (EN): sudo npm install -g LiveScript
.
Vous pouvez aussi le télécharger (zip, tar.gz), ouvrir le dossier, et éxecuter sudo bin/slake install
. En utilisant Git pour télécharger : git clone git://github.com/gkz/LiveScript.git && cd LiveScript && sudo bin/slake install
. Node.js doit être installé sur votre machine.
Vous pouvez aussi l'inclure directement dans le navigateur en incluant le fichier LiveScript/extras/livescript.js
via une balise script. C'est en fait la technique utilisée sur cette page. Si vous utilisez cette méthode, vos scripts LiveScript doivent être à même la page (sans utiliser l'attribut src
), être placés après l'inclusion de livescript.js
, et la balise script doit avoir l'attribut type="text/ls"
.
Utilisation: lsc [options] [fichiers] [arguments]
-i, --interactive | lance le compileur intéractif, utilisez ^J pour du multiligne |
-c, --compile | compile en JavaScript et sauvegarde en .js |
-d, --prelude | importe automatiquement prelude.ls (dans le REPL) |
-k, --const | compile toutes les variables en tant que constantes |
-o, --output DIR | compile dans le dossier de sortie précisé |
-w, --watch | surveille les scripts lors de changements et relance |
-s, --stdin | lis le flux stdin |
-e, --eval | lis les arguments CLI comme script |
-r, --require FILE+ | inclus des bibliothèques avant l'éxecution |
-b, --bare | compile sans l'IIFE globale |
-p, --print | affiche le résultat dans stdout |
-l, --lex | affiche les tokens que le lexer produit |
-t, --tokens | affiche les tokens que le rewriter produit |
-a, --ast | affiche l'arbre syntaxique abstrait que le parser produit |
-j, --json | affiche/compile en tant que JSON |
-n, --nodejs ARGS+ | passe les options à nodejs |
-v, --version | affiche la version |
-h, --help | affiche ceci |
lsc file.ls
— le .ls
est optionnel.
lsc -c file.ls
lsc -wc file.ls
lsc -co output src
lsc -wco output src
lsc -bpe '[1 to 5]'
lsc
— Ctrl-D
pour quitter, utilisez Ctrl-J
pour du multiligne.
Ajoutez vos propres projets à la liste !
Ajoutez le votre dans le wiki (EN).
prelude.ls est la bibliothèque recommandée pour utiliser avec LiveScript. Elle vous permet de faire des choses telles que :
[1 2 3] |> map (* 2) |> filter (> 3) |> fold1 (+) #=> 10
Vous pouvez importer automatiquement prelude.ls via l'option -d
(ou --prelude
) du compilateur.
Vous pouvez tester tous ces exemples en utilisant le compilateur sur la droite.
Pour nettoyer votre code, vous pouvez omettre les parenthèses quand vous appelez une fonction.
add 2, 3
add(2, 3);
Les commentaires sont :
# d'ici à la fin de la ligne.
// d'ici à la fin de la ligne.
Amis de Lisp, vous serez heureux d'apprendre que vous pouvez utiliser les tirets dans vos noms de variables et de fonctions. Ces noms sont identiques à — et compilés vers — leur équivalent camelCase. my-value = 42
== myValue = 42
.
L'extension est .ls
.
Définir une fonction est très simple en LiveScript :
(x, y) -> x + y -> # une fonction vide times = (x, y) -> x * y # multiligne, assignée à une variable # comme en JavaScript
var times; (function(x, y){ return x + y; }); (function(){}); times = function(x, y){ return x * y; };
Comme vous pouvez le voir, les déclarations sont bien plus courtes. Vous pouvez aussi voir que le return
est implicite. En LiveScript, presque tout est une expression et la dernière est automatiquement retournée. Cependant, vous pouvez toujours utiliser return
pour forcer un retour, ou ajouter un point d'exclamation à la définition pour supprimer le retour implicite no-ret = !(x) -> ...
.
L'attribution basique est tout simplement variable = value
, et il n'y a pas besoin de déclarer les variables. Cependant, contrairement à CoffeeScript, vous devez utiliser :=
pour modifier les variables dans des portées supérieures.
x = 10 do -> x = 5 x #=> 10 do -> x := 2 x #=> 2
var x; x = 10; (function(){ var x; return x = 5; })(); x; (function(){ return x = 2; })(); x;
Tout (ou presque) étant une expression, vos attributions peuvent être complexes.
x = if 2 + 2 == 4 then 10 else 0 x #=> 10
var x; x = 2 + 2 === 4 ? 10 : 0; x;
Même les boucles, switch, voire les try/catch sont des expressions.
Si vous voulez simplement déclarer une variable sans l'initialiser, utilisez var
.
var x
var x;
Vous pouvez aussi déclarer des constantes avec le mot-clef const
.
Les vérifications sont faites à la compilation — le JavaScript compilé est le même.
Essayer de compiler le code suivant :
const x = 10 x = 0
Donnera l'erreur suivante : redeclaration of constant "x" on line 2
(re-déclaration de la constante "x" ligne 2
).
À l'inverse, les objets ne sont pas "gêlés" — vous pouvez quand même modifier leurs propriétés. Vous pouvez forcer toutes les variables à être des constantes à l'aide de l'option -k
(ou --const
).
Pour voir les différences avec CoffeeScript, allez au paragraphe Conversion depuis CoffeeScript.
Vous pouvez double-cliquer n'importe quel exemple pour le charger dans le compilateur à droite, ou vous pouvez charger votre propre code. Notez que LiveScript entoure le JavaScript dans une IIFE (function(){...contenu...}).call(this);
— retiré des exemples et des résultats du compilateur pour la concision.
Les nombres littéraux existent comme dans les autres langages. Attention cependant, .4
est invalide, vous devez le précéder d'un zero : 0.4
.
42 17.34 0.4
42; 17.34; 0.4;
Les traits de soulignement (underscores) et autres lettres sont ignorées :
64_000km
64000;
Vous pouvez utiliser n'importe quelle base de 2 à 36 en utilisant ~
:
6~12 2~1000 16~ff
8; 8; 255;
Alias comme en CoffeeScript :
true false on off yes no
true; false; true; false; true; false;
En JavaScript, undefined
peut être redéfini, il est donc plus prudent d'utiliser void
qui produira toujours undefined.
Un void
seul n'est pas inclus dans la compilation (en tant que placeholder) — il peut cependant être utilisé comme valeur :
void x = void null
var x; // void compiles to nothing here! x = void 8; null;
L'utilisation de undefined
comme alias pour void
est déprécié et sera retiré dans la prochaine version de LiveScript. Utilisez void
à la place.
Vous pouvez utiliser des apostrophes ou des guillemets :
'a string' "a string"
'a string'; "a string";
Les chaînes sans espaces peuvent être écrites précédées d'un anti-slash :
\word
'word';
Les chaînes entre guillemets acceptent les interpolations. Les variables simples peuvent être interpolées sans accolades.
"The answer is #{2 + 2}" 'As #{is}' variable = "world" "Hello #variable"
var variable; "The answer is " + (2 + 2); 'As #{is}'; variable = "world"; "Hello " + variable;
Préfixer une interpolation avec %
retourne les parties en tant que liste, vous permettant de les joindre comme bon vous semble.
%"#x #y"
[x, " ", y];
Avec des chaînes multilignes (vous pouvez aussi utiliser des guillemets pour utiliser les interpolations) :
multiline = 'les chaînes peuvent être multilignes \ en continuant tant que nécessaire \ les espaces précédant sont \ ignorés' heredoc = ''' les chaînes peuvent être multilignes en continuant tant que nécessaire les espaces précédant sont ignorés ''' nospace = 'deadbeef deadbeef'
var multiline, heredoc, nospace; multiline = 'les chaînes peuvent être multilignes en continuant tant que nécessaire les espaces précédant sont ignorés'; heredoc = 'les chaînes peuvent être multilignes\nen continuant tant que nécessaire\nles espaces précédant sont\nignorés'; nospace = 'deadbeefdeadbeef';
Les commentaires monoligne commencent avec un #
. Ils sont supprimés à la compilation.
# commentaire
Les commentaires multiligne sont gardés
/* Utilisez ce format pour conserver vos commentaires */
/* Utilisez ce format pour conserver vos commentaires */
Les accolades sont optionnelles :
obj = {prop: 1, thing: 'moo'} person = age: 23 eye-color: \green height: 180cm oneline = color: \blue, heat: 4
var obj, person, oneline; obj = { prop: 1, thing: 'moo' }; person = { age: 23, eyeColor: 'green', height: 180 }; oneline = { color: 'blue', heat: 4 };
Les clefs peuvent être dynamiques :
obj = "#variable": 234 (person.eye-color): false
var obj, ref$; obj = (ref$ = {}, ref$[variable + ""] = 234, ref$[person.eyeColor] = false, ref$);
Raccourci pour les propriétés — vous permet d'utiliser plus rapidement des variables quand la clef est le nom de la variable en valeur :
x = 1 y = 2 obj = {x, y}
var x, y, obj; x = 1; y = 2; obj = { x: x, y: y };
Raccourci pour les booléens :
{+debug, -live}
({ debug: true, live: false });
This — pas besoin d'utiliser de .
pour accéder aux propriétés.
this @ @location
this; this; this.location;
Les expressions régulières sont délimitées avec un simple /
.
/moo/gi
/moo/gi;
Lorsque délimitées avec //
, vous pouvez utiliser des espaces, des interpolations et les écrire sur plusieurs lignes
// | [!=]==? # équalité | @@ # constructor | <\[(?:[\s\S]*?\]>)? # mots //g
/|[!=]==?|@@|<\[(?:[\s\S]*?\]>)?/g;
Les listes simples sont entre crochets :
[1, person.age, 'French Fries']
[1, person.age, 'French Fries'];
Les virgules ne sont pas nécessaires si l'élément précédent n'est pas appellable :
[1 2 3 true void \word 'hello there']
[1, 2, 3, true, void 8, 'word', 'hello there'];
Vous pouvez créer des listes implicites en indentant un bloc. Vous devez avoir au moins deux éléments pour que cela fonctionne. Si vous n'en avez qu'un, utilisez le yaddayaddayadda ...
:
my-list = 32 + 1 person.height \beautiful one-item = 1 ...
var myList, oneItem; myList = [32 + 1, person.height, 'beautiful']; oneItem = [1];
Quand vous utilisez des listes implicites, vous pouvez utiliser un astérisque *
pour désambiguïser entre les structures.
L'astérique ne représente pas un élément de la liste, mais indente en fait une structure implicite pour ne pas qu'elle soit mélangée avec les autres.
tree = * 1 * 2 3 4 * 5 6 * 7 8 * 9 10 11 obj-list = * name: \tessa age: 23 * name: \kendall age: 19 obj = * name: \tessa age: 23 obj-one-list = * name: \tessa age: 23 ...
var tree, objList, obj, objOneList; tree = [[1, [2, 3], 4], [5, 6, [7, 8, [9, 10]], 11]]; objList = [ { name: 'tessa', age: 23 }, { name: 'kendall', age: 19 } ]; obj = { name: 'tessa', age: 23 }; objOneList = [{ name: 'tessa', age: 23 }];
Liste de mots :
<[ list of words ]>
['list', 'of', 'words'];
Dans une série, to
signifie à, et inclus le nombre à droite. til
signifie jusqu'à et n'inclus pas le nombre.
Vous pouvez optionnellement ajouter un by
qui définira l'étape.
Si vous omettez le premier nombre, il sera 0
.
Avec des nombres/chaînes littéraux :
[1 to 5] #=> [1, 2, 3, 4, 5] [1 til 5] #=> [1, 2, 3, 4] [1 to 10 by 2] #=> [1, 3, 7, 9] [4 to 1] #=> [4, 3, 2, 1] [to 5] #=> [0, 1, 2, 3, 4, 5] [\A to \D] #=> ['A', 'B', 'C', D']
[1, 2, 3, 4, 5]; [1, 2, 3, 4]; [1, 3, 5, 7, 9]; [4, 3, 2, 1]; [0, 1, 2, 3, 4, 5]; ["A", "B", "C", "D"];
Avec n'importe quelle expression — si vous voulez aller vers le bas (d'un nombre à un autre plus petit), vous devez le préciser explicitement avec by -1
.
x = 4 [1 to x] #=> [1, 2, 3, 4] [x to 0 by -1] #=> [4, 3, 2, 1, 0]
var x, i$; x = 4; for (i$ = 1; i$ <= x; ++i$) { i$; } for (i$ = x; i$ >= 0; --i$) { i$; }
Labels (utile pour les boucles imbriquées ainsi qu'avec les blocs comme let
) :
:label 4 + 2
label: { 4 + 2; }
Raccourci pour constructor
:
@@ @@x x@@y
constructor; constructor.x; x.constructor.y;
Yaddayaddayadda — un espace réservé :
...
throw Error('unimplemented');
Les opérateurs mathématiques standarts :
1 + 2 #=> 3 3 - 4 #=> -1 6 * 2 #=> 12 8 / 4 #=> 2
1 + 2; 3 - 4; 6 * 2; 8 / 4;
Il y a aussi un opérateur pour obtenir le reste d'une division, comme en JavaScript — ainsi que le modulo :
-3 % 4 #=> -3 -3 %% 4 #=> 1
var ref$; -3 % 4; ((-3) % (ref$ = 4) + ref$) % ref$;
L'opérateur de puissance est associatif à droite, et a une plus haute précédence que les opérateurs unaires. ^
est un alias pour **
:
2 ** 4 #=> 16 3 ^ 4 #=> 81 -2 ^ 2 ^ 3 #=> -256
Math.pow(2, 4); Math.pow(3, 4); -Math.pow(2, Math.pow(2, 3));
Incrémentation, décrementation :
n = 0 n++ #=> 0 ++n #=> 2 n-- #=> 2 --n #=> 0 x = n++ #=> 0 x #=> 0 n #=> 1 x = ++n #=> 2 x #=> 2 n #=> 2
var n, x; n = 0; n++; ++n; n--; --n; x = n++; x; n; x = ++n; x; n;
Opérateurs de bits et de décalage :
14 .&. 9 #=> 8 14 .|. 9 #=> 15 14 .^. 9 #=> 7 ~9 #=> -10 9 .<<. 2 #=> 36 -9 .>>. 2 #=> -3 -9 .>>>. 2 #=> 1073741821
14 & 9; 14 | 9; 14 ^ 9; ~9; 9 << 2; -9 >> 2; -9 >>> 2;
Conversion vers un nombre :
+'4' #=> 4 -'3' #=> -3
+'4'; -'3';
Égalité stricte (pas de conversion de type) :
2 + 4 == 6 #=> true \boom is 'boom' #=> true \boom != null #=> true 2 + 2 is not 4 #=> false 0 + 1 isnt 1 #=> false
2 + 4 === 6; 'boom' === 'boom'; 'boom' !== null; 2 + 2 !== 4; 0 + 1 !== 1;
Égalité simple (avec conversion de type) :
2 ~= '2' #=> true \1 !~= 1 #=> false
2 == '2'; '1' != 1;
Supérieur/inférieur à :
2 < 4 #=> true 9 > 7 #=> true 8 <= 8 #=> true 7 >= 8 #=> false
2 < 4; 9 > 7; 8 <= 8; 7 >= 8;
Enchaînement de comparaisons :
1 < 2 < 4 #=> true 1 < 2 == 4/2 > 0 #=> true
var ref$; 1 < 2 && 2 < 4; 1 < 2 && 2 === (ref$ = 4 / 2) && ref$ > 0;
Minimum/maximum — retourne le minimum/maximum des deux opérandes :
4 >? 8 #=> 8 9 - 5 <? 6 #=> 4
var ref$; 4 > 8 ? 4 : 8; (ref$ = 9 - 5) < 6 ? ref$ : 6;
Quand une des deux opérandes d'une comparaison (==
ou is
, ainsi que les versions inversées) est une expression régulière littérale, elle sera testée contre l'autre opérande.
Une égalité donne un appel d'exec
pour que vous puissiez utiliser les résultats, alors qu'une inégalité utilise test
pour les performances.
/^e(.*)/ is 'enter' #=> ["enter","nter"] /^e(.*)/ == 'zx' #=> null /moo/ != 'loo' #=> true
/^e(.*)/.exec('enter'); /^e(.*)/.exec('zx'); !/moo/.test('loo');
Les bases :
true and false #=> false true && false #=> false true or false #=> true true || false #=> true not false #=> true !false #=> true
true && false; true && false; true || false; true || false; !false; !false;
Ou exclusif — un opérateur peu vu dans d'autres langages.
false xor true #=> true false xor false #=> false 1 xor 0 #=> 1 1 xor 1 #=> false
!false !== !true && (false || true); !false !== !false && (false || false); !1 !== !0 && (1 || 0); !1 !== !1 && (1 || 1);
and
, or
, et xor
ferment les appels implicites, contrairement à ||
et &&
:
even 0 and 3 #=> 3 even 0 && 3 #=> true
even(0) && 3; even(0 && 3);
Vous pouvez appeler les opérateurs logiques :
(f or g) 1 (f and g or h) 3 4
f(1) || g(1); f(3, 4) && g(3, 4) || h(3, 4);
Vous n'êtes pas limités aux variables ici ! Vous pouvez utiliser les littéraux.
('a' || /b/ && f) c
'a' === c || /b/.exec(c) && f(c);
Utilisez in
pour savoir si un élément est dans une liste, et of
pour savoir si l'objet contient une clef :
list = [7 8 9] 2 in [1 2 3 4 5] #=> true 3 in list #=> false \id of id: 23, name: \rogers #=> true
var list; list = [7, 8, 9]; 2 === 1 || 2 === 2 || 2 === 3 || 2 === 4 || 2 === 5; in$(3, list); 'id' in { id: 23, name: 'rogers' }; function in$(x, xs){ var i = -1, l = xs.length >>> 0; while (++i < l) if (x === xs[i]) return true; return false; }
À la place d'une série d'appels imbriqués, vous pouvez utiliser le piping. x |> f
et f <| x
sont équivalents à f(x)
.
[1 2 3] |> reverse |> head #=> 3 reverse <| [1 2 3] #=> [3,2,1]
head( reverse( [1, 2, 3])); reverse([1, 2, 3]);
Le piping est bien sûr multiligne, pour plus de clarté.
4 |> (+ 1) |> even #=> false
even( (function(it){ return it + 1; })( 4));
Vous pouvez utiliser le piping directement après une expression, comme par exemple un for
:
for a in <[fi bu ba]> "#{a}zz" |> map (.toUpperCase!) |> (* ', ')
var a, join$ = [].join; (function(it){ return join$.call(it, ', '); })( map(function(it){ return it.toUpperCase(); })( (function(){ var i$, ref$, len$, results$ = []; for (i$ = 0, len$ = (ref$ = ['fi', 'bu', 'ba']).length; i$ < len$; ++i$) { a = ref$[i$]; results$.push(a + "zz"); } return results$; }())));
La composition vous permet de créer des fonctions composées d'autres fonctions. LiveScript a deux opérateurs pour : avant (>>
) et arrière (<<
).
(f << g) x
est pareil que f(g(x))
, et (f >> g) x
est équivalent à g(f(x))
.
odd = (not) << even odd 3 #=> true
var odd; odd = compose$(even, not$); odd(3); function compose$() { var functions = arguments; return function() { var i, result; result = functions[0].apply(this, arguments); for (i = 1; i < functions.length; ++i) { result = functions[i](result); } return result; }; } function not$(x){ return !x; }
Pour être un peu plus clair à propos des différences entre les deux opérateurs :
add-two-times-two = (+ 2) >> (* 2) times-two-add-two = (+ 2) << (* 2) add-two-times-two 3 #=> (3+2)*2 = 10 times-two-add-two 3 #=> (3*2)+2 = 8
var addTwoTimesTwo, timesTwoAddTwo; addTwoTimesTwo = compose$((function(it){ return it + 2; }), (function(it){ return it * 2; })); timesTwoAddTwo = compose$((function(it){ return it * 2; }), (function(it){ return it + 2; })); addTwoTimesTwo(3); timesTwoAddTwo(3); function compose$() { var functions = arguments; return function() { var i, result; result = functions[0].apply(this, arguments); for (i = 1; i < functions.length; ++i) { result = functions[i](result); } return result; }; }
Vous pouvez aussi utiliser un point espacé comme alias pour <<
,
par exemple f . g
, comme en Haskell.
Vous pouvez concaténer deux listes ensemble : (attention, l'opérateur doit être doublement espacé)
<[ un deux trois ]> ++ [\quatre] #=> ['un','deux','trois','quatre']
['un', 'deux', 'trois'].concat(['quatre']);
Répétition :
[\ha] * 3 #=> ['ha','ha','ha']
['ha', 'ha', 'ha'];
Jointure :
<[ one two three ]> * \| #=> 'one|two|three'
['one', 'two', 'three'].join('|');
Propagation unaire — quand l'opérande est une liste littérale, l'opérateur unaire est appliqué à tous les éléments :
r = +...[4 5 6] #=> [+4, +5, +6] t = typeof! ...[\b 5 {}] #=> ["String", "Number", "Object"] c = ~...[4, 5] #=> [-5, -6] ++...player<[strength hp]> # marche aussi avec -, --, typeof, # ! et delete! voire -~-~ i = new ...[some, classes] c = ^^...[copy, these, {}] delete ...list[1, 2, 3] do ...[a, b, c]
var r, t, c, i, toString$ = {}.toString; r = [+4, +5, +6]; t = [toString$.call('b').slice(8, -1), toString$.call(5).slice(8, -1), toString$.call({}).slice(8, -1)]; c = [~4, ~5]; ++player['strength'], ++player['hp']; i = [new some, new classes]; c = [clone$(copy), clone$(these), clone$({})]; delete list[1], delete list[2], delete list[3]; a(), b(), c(); function clone$(it){ function fun(){} fun.prototype = it; return new fun; }
Concaténation :
'hello' + ' ' + 'world' #=> 'hello world' string = 'say ' #=> 'say ' string += \yeah #=> 'say yeah'
var string; 'hello' + ' ' + 'world'; string = 'say '; string += 'yeah';
Répétition :
'X' * 3 #=> 'XXX'
'XXX';
Soustraction / division de chaînes — soustraction pour replace
, division pour split
.
'say yeah' - /h/ #=> 'say yea' 'say yeah' / \y #=> ['sa',' ','eah']
'say yeah'.replace(/h/, ''); 'say yeah'.split('y');
L'opérateur ?
peut être utilisé dans de nombreux contextes pour vérifier une présence.
bigfoot ? 'grizzly bear' #=> 'grizzly bear' string = \boom if window? #=> 'boom' document?.host #=> 'gkz.github.com'
var string; (typeof bigfoot == 'undefined' || bigfoot === null) && 'grizzly bear'; if (typeof window != 'undefined' && window !== null) { string = 'boom'; } if (typeof document != 'undefined' && document !== null) { document.host; }
instanceof
— les listes littérales sur la droite sont étendues (propagation unaire).
new Date() instanceof Date #=> true new Date() instanceof [Date, Object] #=> true
var ref$; new Date() instanceof Date; (ref$ = new Date()) instanceof Date || ref$ instanceof Object;
typeof
— ainsi que la variante LiveScript avec un point d'exclamation :
typeof /^/ #=> object typeof! /^/ #=> RegEx
var toString$ = {}.toString; typeof /^/; toString$.call(/^/).slice(8, -1);
delete
retourne la valeur de l'élément supprimé :
obj = {one: 1, two: 2} r = delete obj.one r #=> 1
var obj, r, ref$; obj = { one: 1, two: 2 }; r = (ref$ = obj.one, delete obj.one, ref$); r;
delete!
est l'équivalent de delete
en JavaScript, et retourne false
uniquement si la propriété existe mais ne peut être supprimée :
obj = {one: 1, two: 2} delete! obj.one #=> true delete! Math.PI #=> false
var obj; obj = { one: 1, two: 2 }; delete obj.one; delete Math.PI;
Copie de propriétés — de droite à
gauche. <<<
pour les propriétés propres (Object.hasOwnProperty
), <<<<
pour toutes les propriétés. import
et import all
sont des alias. Si vous omettez l'opérande gauche, this
est implicite.
obj = {one: 1, two: 2} obj <<< three: 3 #=> {one: 1, two: 2, three: 3} {go: true} <<<< window import obj
var obj; obj = { one: 1, two: 2 }; obj.three = 3; importAll$({ go: true }, window); import$(this, obj); function importAll$(obj, src){ for (var key in src) obj[key] = src[key]; return obj; } function import$(obj, src){ var own = {}.hasOwnProperty; for (var key in src) if (own.call(src, key)) obj[key] = src[key]; return obj; }
Clonage — clone le prototype de l'opérande. Ne clone pas en profondeur, à la place, l'opérande sera le prototype de l'objet cloné.
Souvenez-vous que la sérialisation JSON ne montre pas les prototypes.
obj = {one: 1} obj2 = ^^obj obj2.two = 2 obj2 #=> {one: 1, two: 2} # ci-dessus avec les propriétés du prototype # la sérialisation JSON donnerait `{two: 2}` obj #=> {one: 1}
var obj, obj2; obj = { one: 1 }; obj2 = clone$(obj); obj2.two = 2; obj2; obj; function clone$(it){ function fun(){} fun.prototype = it; return new fun; }
Le with infixe (ou cloneport) combine le clonage et la copie de propriétés. Il est équivalent à ^^obj <<< obj2
Souvenez-vous que le clonage est un clonage prototypal, et que la sérialisation JSON ne montre pas les prototypes.
girl = {name: \hanna, age: 22} guy = girl with name: \john guy #=> {name: 'john', age: 22} # ci-dessus avec les propriétés du prototype # la sérialisation JSON donnerait `{name: 'john'}` girl #=> {name: 'hanna', age: 22}
var girl, guy, ref$; girl = { name: 'hanna', age: 22 }; guy = (ref$ = clone$(girl), ref$.name = 'john', ref$); guy; girl; function clone$(it){ function fun(){} fun.prototype = it; return new fun; }
Vous pouvez "appliquer partiellement" les opérateurs pour les utiliser en tant que fonctions :
(+ 2) 4 #=> 6 (*) 4 3 #=> 12 (not) true #=> false (in [1 to 3]) 2 #=> true
(function(it){ return it + 2; })(4); curry$(function(x$, y$){ return x$ * y$; })(4, 3); not$(true); (function(it){ return it === 1 || it === 2 || it === 3; })(2); function curry$(f, bound){ var context, _curry = function(args) { return f.length > 1 ? function(){ var params = args ? args.concat() : []; context = bound ? context || this : this; return params.push.apply(params, arguments) < f.length && arguments.length ? _curry.call(context, params) : f.apply(context, params); } : f; }; return _curry(); } function not$(x){ return !x; }
Avoir beaucoup de modules signifie beaucoup de redondance dans les inclusions. Avec require!
, qui prend identifieur(s), chaîne, liste ou objet, vous pouvez éviter cette redondance.
Si vous voulez inclure un module avec des tirets, vous devez utiliser une chaîne.
Vous pouvez renommer ce que vous incluez en utilisant un objet littéral.
require! lib require! 'lib1' require! prelude-ls # no require! 'prelude-ls' require! [fs, path] require! <[ fs path ]> require! jQuery: $ require! { fs path lib4: lib }
var lib, lib1, preludeLs, fs, path, $; lib = require('lib'); lib1 = require('lib1'); preludeLs = require('preludeLs'); preludeLs = require('prelude-ls'); fs = require('fs'); path = require('path'); fs = require('fs'); path = require('path'); $ = require('jQuery'); fs = require('fs'); path = require('path'); lib = require('lib4');
Vous pouvez aussi inclure des parties de modules :
require! { lib lib:{part1} }
var lib, part1; lib = require('lib'); part1 = require('lib').part1;
Les noms de fichier sont extraits :
require! 'lib.js' require! './dir/lib1.js'
var lib, lib1; lib = require('lib.js'); lib1 = require('./dir/lib1.js');
La définition de fonction est très simple en LiveScript :
(x, y) -> x + y -> # une fonction vide times = (x, y) -> x * y # multiligne, assignée à une variable # comme en JavaScript
var times; (function(x, y){ return x + y; }); (function(){}); times = function(x, y){ return x * y; };
Comme vous pouvez le voir, les déclarations sont bien plus courtes. Vous pouvez aussi voir que le return
est implicite. En LiveScript, presque tout est une expression et la dernière est automatiquement retournée. Cependant, vous pouvez toujours utiliser return
pour forcer un retour, ou ajouter un point d'exclamation à la définition pour supprimer le retour implicite no-ret = (x) !-> ...
.
f = !-> 2 g = (x) !-> x + 2
var f, g; f = function(){ 2; }; g = function(x){ x + 2; };
vous pouvez omettre les parenthèses quand vous appelez une fonction, et comme pour les listes, vous pouvez omettre la virgule entre les arguments si l'argument précédent n'est pas appellable :
x = 4 Math.pow x, 3 #=> 64 Math.pow 2 3 #=> 8
var x; x = 4; Math.pow(x, 3); Math.pow(2, 3);
Si vous appelez une fonction sans arguments, vous pouvez utiliser !
— vous n'avez pas besoin non plus de point pour enchaîner les fonctions ainsi appelées.
f! [1 2 3].reverse!slice 1 #=> [2,1]
f(); [1, 2, 3].reverse().slice(1);
and
, or
, xor
, un .
espacé ou ?.
ferment les appels implcites — permettant d'enchaîner les appels sans parenthèses.
$ 'h1' .find 'a' .text! #=> LiveScript
$('h1').find('a').text();
Vous pouvez utiliser do
pour transformer un bloc de code en un appel (et appeler une fonction sans arguments) :
do -> 3 + 2 #=> 5 calc = five: do 3 + 2
var calc; (function(){ return 3 + 2; })(); calc = { five: 3 + 2 };
Si vous utilisez do
sur une fonction nommée, et que le do
n'est pas utilisé en tant qu'expression, l'appel appellera la fonction directement :
i = 0 f 9 #=> 9 i #=> 1 do function f x ++i x i #=> 2
var i; i = 0; f(9); i; function f(x){ ++i; return x; } f(); i;
Utilisez do
pour appeler une function avec un objet implicite :
func do a: b c: d
func({ a: b, c: d });
do
sert en vérité à bien plus que ça - c'est une construction permettant de créer un Block et donc d'éviter les parenthèses :
pow do 1 2 h 1 do a: 2 b: 5
pow(1, 2); h(1, { a: 2, b: 5 });
Vous pouvez appeler des fonctions infixes avec `
.
add = (x, y) -> x + y 3 `add` 4 #=> 7
var add; add = function(x, y){ return x + y; }; add(3, 4);
Appeler une fonction avec l'opérateur reste (splat) ...
lui passe les arguments de la fonction actuelle. C'est particulièrement utile avec super
.
f = (x, y) -> x + y g = (a, b) -> f ... g 3 4 #=> 7
var f, g; f = function(x, y){ return x + y; }; g = function(a, b){ return f.apply(this, arguments); }; g(3, 4);
Paramètres étendus :
set-person-params = ( person # objet cible person.age person.height ) -> person person = set-person-params {}, 21, 180cm #=> {age: 21, height: 180}
var setPersonParams, person; setPersonParams = function(person, age, height){ person.age = age; person.height = height; return person; }; person = setPersonParams({}, 21, 180);
Particulièrement utile avec this
:
set-text = (@text) -> this
var setText; setText = function(text){ this.text = text; return this; };
Vous pouvez donner des valeurs par défault aux arguments :
add = (x = 4, y = 3) -> x + y add 1 2 #=> 3 add 1 #=> 4 add! #=> 7
var add; add = function(x, y){ x == null && (x = 4); y == null && (y = 3); return x + y; }; add(1, 2); add(1); add();
... ou utiliser n'importe quel opérateur logique (dans les paramètres, x = 2
correspond à x ? 2
):
add = (x && 4, y || 3) -> x + y add 1 2 #=> 6 add 2 0 #=> 7
var add; add = function(x, y){ x && (x = 4); y || (y = 3); return x + y; }; add(1, 2); add(2, 0);
Vous pouvez aussi déstructurer les arguments :
set-cords = ({x, y}) -> "#x,#y" set-cords y: 2, x: 3 #=> '3,2'
var setCords; setCords = function(arg$){ var x, y; x = arg$.x, y = arg$.y; return x + "," + y; }; setCords({ y: 2, x: 3 });
... et aller jusqu'à donner des valeurs par défaults, ou utiliser n'importe quel opérateur logique dans ces paramètres déstructurés :
set-cords = ({x = 1, y = 3} = {}) -> "#x,#y" set-cords y: 2, x: 3 #=> '3,2' set-cords x: 2 #=> '2,3' set-cords y: 7 #=> '1,7' set-cords! #=> '1,3'
var setCords; setCords = function(arg$){ var ref$, x, ref1$, y; ref$ = arg$ != null ? arg$ : {}, x = (ref1$ = ref$.x) != null ? ref1$ : 1, y = (ref1$ = ref$.y) != null ? ref1$ : 3; return x + "," + y; }; setCords({ y: 2, x: 3 }); setCords({ x: 2 }); setCords({ y: 7 }); setCords();
Vous pouvez aussi obtenir le reste (splat) des paramètres :
f = (x, ...ys) -> x + ys.1 f 1 2 3 4 #=> 4
var f; f = function(x){ var ys, res$, i$, to$; res$ = []; for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { res$.push(arguments[i$]); } ys = res$; return x + ys[1]; }; f(1, 2, 3, 4);
Les fonctions currifiées sont très puissantes. Pour faire simple, les fonctions appelées avec moins d'arguments qu'elles n'en ont retournent une fonction partiellement appliquée qui acceptera le reste des arguments. En LiveScript, ces fonctions sont définiés avec une longue flèche :
times = (x, y) --> x * y times 2, 3 #=> 6 (fonctionnement normal) double = times 2 double 5 #=> 10
var times, double; times = curry$(function(x, y){ return x * y; }); times(2, 3); double = times(2); double(5); function curry$(f, bound){ var context, _curry = function(args) { return f.length > 1 ? function(){ var params = args ? args.concat() : []; context = bound ? context || this : this; return params.push.apply(params, arguments) < f.length && arguments.length ? _curry.call(context, params) : f.apply(context, params); } : f; }; return _curry(); }
Vous pouvez définir des fonctions liées avec une longue flèche ondulée : ~~>
Vous pouvez créer des fonctions nommées, utilisables n'importe où dans le fichier même si définies à la fin. Ces fonctions sont constantes et ne peuvent être redéfinies.
LiveScript ne touche pas au bug JScript (EN).
util! #=> 'disponible avant déclaration' util2! #=> 2 function util 'disponible avant déclaration' function util2 then 2
util(); util2(); function util(){ return 'disponible avant déclaration'; } function util2(){ return 2; }
Vous pouvez lier la fonction en ajoutant un ~
:
~function add x, y @result = x + y
var this$ = this; function add(x, y){ return this$.result = x + y; }
Vous pouvez aussi ajouter un !
pour supprimer le return
implicite :
util! #=> nothing !function util(x) x
util(); function util(x){ x; }
Vous pouvez bien sûr combiner ~
et !
pour créer une fonction liée sans retour implicite.
Les fonctions liées sont définies avec une flèche ondulée ~>
. Utilisez la version longue pour les fonctions liées et currifiées ~~>
.
Les fonctions liées ont leur this
lié lexicalement, pas dynamiquement, ce qui signifie que leur this
restera l'original, quel que soit le contexte.
obj = new @x = 10 @normal = -> @x @bound = ~> @x obj2 = x: 5 obj2.normal = obj.normal obj2.bound = obj.bound obj2.normal! #=> 5 obj2.bound! #=> 10
var obj, obj2; obj = new function(){ var this$ = this; this.x = 10; this.normal = function(){ return this.x; }; this.bound = function(){ return this$.x; }; }; obj2 = { x: 5 }; obj2.normal = obj.normal; obj2.bound = obj.bound; obj2.normal(); obj2.bound();
Référez-vous au paragraphe sur la POO pour plus d'informations sur les fonctions liées dans les classes.
let
est un raccourci pour (function(a){...}.call(this, b))
.
let $ = jQuery $.isArray [] #=> true
(function($){ $.isArray([]); }.call(this, jQuery));
Vous pouvez aussi définir le this
(ou @
) avec let
.
x = let @ = a: 1, b: 2 @b ^ 3 x #=> 8
var x; x = (function(){ return Math.pow(this.b, 3); }.call({ a: 1, b: 2 })); x;
Création de contexte :
dog = new @name = \spot @mutt = true #=> {name: 'spot', mutt: true}
var dog; dog = new function(){ this.name = 'spot'; this.mutt = true; };
Particulièrement utile avec des fonctions de haut niveau telles que map
et filter
.
(.prop)
est un raccourci pour (it) -> it.prop
.
map (.length), <[ hello there you ]> #=> [5,5,3] filter (.length < 4), <[ hello there you ]> #=> ['you']
map(function(it){ return it.length; }, ['hello', 'there', 'you']); filter(function(it){ return it.length < 4; }, ['hello', 'there', 'you']);
Vous pouvez bien sûr appeler des méthodes :
map (.join \|), [[1 2 3], [7 8 9]] #=> ['1|2|3','7|8|9']
map(function(it){ return it.join('|'); }, [[1, 2, 3], [7, 8, 9]]);
(obj.)
est un raccourci pour (it) -> obj[it]
.
obj = one: 1, two: 2, three: 3 map (obj.), <[ one three ]> #=> [1,3]
var obj; obj = { one: 1, two: 2, three: 3 }; map(function(it){ return obj[it]; }, ['one', 'three']);
Les rappels désimbriqués (backcalls) sont très utiles. Ils vous permettent de désimbriquer vos rappels. La syntaxe est la même que pour les fonctions, mais avec la flèche vers la gauche (<~
, <--
, <~~
, <-!
) :
<- $ alert 'boom'
$(function(){ return alert('boom'); });
Vous pouvez ajouter des arguments, et réserver un espace si l'ordre des arguments ne vous convient pas :
x <- map _, [1 to 3] x * 2 #=> [2, 4, 6]
map(function(x){ return x * 2; }, [1, 2, 3]);
Si vous voulez rajouter du code après, vous pouvez indenter vos rappels arrières grâce à do
.
do data <-! $.get 'ajaxtest' $ '.result' .html data processed <-! $.get 'ajaxprocess', data $ '.result' .append processed alert 'hi'
$.get('ajaxtest', function(data){ $('.result').html(data); $.get('ajaxprocess', data, function(processed){ $('.result').append(processed); }); }); alert('hi');
Si vous voulez des fonctionnalités asynchrones avancées, vous pouvez utiliser async.js avec LiveScript.
Vous pouvez appliquer partiellement des fonctions avec _
comme espace réservé, si l'ordre des arguments ne vous convient pas ou si la fonction n'est pas currifiée :
filter-nums = filter _, [1 to 5] filter-nums even #=> [2,4] filter-nums odd #=> [1,3,5] filter-nums (< 3) #=> [1,2]
var filterNums, slice$ = [].slice; filterNums = partialize$.apply(this, [filter, [void 8, [1, 2, 3, 4, 5]], [0]]); filterNums(even); filterNums(odd); filterNums((function(it){ return it < 3; })); function partialize$(f, args, where){ var context = this; return function(){ var params = slice$.call(arguments), i, len = params.length, wlen = where.length, ta = args ? args.concat() : [], tw = where ? where.concat() : []; for(i = 0; i < len; ++i) { ta[tw[0]] = params[i]; tw.shift(); } return len < wlen && len ? partialize$.apply(context, [f, ta, tw]) : f.apply(context, ta); }; }
Si vous appelez une fonction partiellement appliquée sans arguments, elle sera éxecutée plutôt que de se retourner elle-même, vous permettant d'utiliser des arguments par défaut
Cette syntaxe est particulièrement intéressante avec le piping lorsqu'utilisée avec des bibliothèques n'ayant pas une syntaxe adaptée (comme underscore.js).
[1 2 3] |> _.map _, (* 2) |> _.reduce _, (+), 0 #=> 12
_.reduce(_.map([1, 2, 3], (function(it){ return it * 2; })), curry$(function(x$, y$){ return x$ + y$; }), 0); function curry$(f, bound){ var context, _curry = function(args) { return f.length > 1 ? function(){ var params = args ? args.concat() : []; context = bound ? context || this : this; return params.push.apply(params, arguments) < f.length && arguments.length ? _curry.call(context, params) : f.apply(context, params); } : f; }; return _curry(); }
Si vous n'avez qu'un seul argument, vous pouvez utiliser it
pour y accéder sans avoir à le lister :
f = -> it + 2 f 3 #=> 5
var f; f = function(it){ return it + 2; }; f(3);
Vous pouvez accéder à l'objet arguments
avec le raccourci &
. Le premier argument est &0
, le second &1
, etc. &
seul correspond à arguments
.
add-three-numbers = -> &0 + &1 + &2 add-three-numbers 1 2 3 #=> 6
var addThreeNumbers; addThreeNumbers = function(){ return arguments[0] + arguments[1] + arguments[2]; }; addThreeNumbers(1, 2, 3);
Notez que la currification ne marche pas dans cette situation, car le nombre d'arguments déclarés de add-three-numbers
est 0.
Référez-vous au paragraphe sur la composition de fnctions, ainsi que sur le piping.
Il y a plusieurs manières de formater un if
(en fait une expression).
Le standard:
if 2 + 2 == 4 'quelque chose' else 'quelque chose d\'autre' if 2 + 2 == 4 then 'quelque chose' else 'quelque chose d\'autre' if 2 + 2 == 4 then 'quelque chose' else 'quelque chose d\'autre'
if (2 + 2 === 4) { 'quelque chose'; } else { 'quelque chose d\'autre'; } if (2 + 2 === 4) { 'quelque chose'; } else { 'quelque chose d\'autre'; } if (2 + 2 === 4) { 'quelque chose'; } else { 'quelque chose d\'autre'; }
Le else
est bien sûr optionnel, et vous pouvez ajouter des else if
.
if 2 + 2 == 4 'quelque chose' if 2 + 2 == 6 'quelque chose' else if 2 + 2 == 5 'quelque chose d\'autre' else 'par défaut'
if (2 + 2 === 4) { 'quelque chose'; } if (2 + 2 === 6) { 'quelque chose'; } else if (2 + 2 === 5) { 'quelque chose d\'autre'; } else { 'par défaut'; }
Aussi utilisable en tant qu'expression :
result = if 2 / 2 is 0 then 'quelque chose' else 'quelque chose d\'autre'
var result; result = 2 / 2 === 0 ? 'quelque chose' : 'quelque chose d\'autre';
Aussi utilisable après une expression — ayant une précédence plus basse que l'égalité, rendant ceci possible :
x = 10 x = 3 if 2 + 2 == 4 x #=> 3
var x; x = 10; if (2 + 2 === 4) { x = 3; } x;
unless
est l'équivalent de if not
.
unless 2 + 2 == 5 'quelque chose' x = 10 x = 3 unless 2 + 2 == 5
var x; if (2 + 2 !== 5) { 'quelque chose'; } x = 10; if (2 + 2 !== 5) { x = 3; }
that
réfère implicitement à la valeur de la condition — ignorant les vérifications d'existences (?
). Dans un if
, dans un switch case
ou avec when
(et leur version inverse).
time = days: 365 half-year = that / 2 if time.days #=> 182.5 if /^e(.*)/ == 'enter' that.1 #=> 'nter' if half-year? that * 2 #=> 365
var time, that, halfYear; time = { days: 365 }; if (that = time.days) { halfYear = that / 2; } if (that = /^e(.*)/.exec('enter')) { that[1]; } if ((that = halfYear) != null) { that * 2; }
Les boucles for
ont la structure suivante : for (let) (from) (to|til) (by) (when)
— (tout est optionnel).
by
est l'étape, par défaut 1
.
from
, si omis, est 0
.
when
, (alias case
ou |
) est un guard optionnel (comme un if
).
let
permet de capturer les variables dans une fonction auto-invoquée, empêchant aussi les variables créées dans la boucle d'exister dans les portées supérieures.
Utilisez in
pour itérer dans une liste, of
et of dans un objet.
Si utilisé comme expression, les boucles renvoient des listes.
for i from 1 to 10 by 3 i for val, i in [7 8 9] val for key, val of {one: 1, two: 2} key
var i$, i, ref$, len$, val, key; for (i$ = 1; i$ <= 10; i$ += 3) { i = i$; i; } for (i$ = 0, len$ = (ref$ = [7, 8, 9]).length; i$ < len$; ++i$) { i = i$; val = ref$[i$]; val; } for (key in ref$ = { one: 1, two: 2 }) { val = ref$[key]; key; }
Les boucles normales (for
/while
) imbriquées renvoient des listes de listes :
result = for x to 3 for y to 2 x + y result #=> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
var result, res$, i$, x, lresult$, j$, y; res$ = []; for (i$ = 0; i$ <= 3; ++i$) { x = i$; lresult$ = []; for (j$ = 0; j$ <= 2; ++j$) { y = j$; lresult$.push(x + y); } res$.push(lresult$); } result = res$; result;
Vous pouvez omettre une ou les deux variable dans une boucle in
/of
:
res = for , i in [1 2 3] i res #=> [0, 1, 2] for til 3 then func! # calls func three times [6 for til 3] #=> [6, 6, 6]
var res, res$, i$, len$, i; res$ = []; for (i$ = 0, len$ = [1, 2, 3].length; i$ < len$; ++i$) { i = i$; res$.push(i); } res = res$; res; for (i$ = 0; i$ < 3; ++i$) { func(); } for (i$ = 0; i$ < 3; ++i$) { 6; }
Les compréhensions de listes, même multiples, renvoient des listes non imbriquées :
[x + 1 for x to 10 by 2 when x isnt 4] #=> [1,3,7,9,11] ["#x#y" for x in [\a \b] for y in [1 2]] #=> ['a1','a2','b1','b2']
var i$, x, ref$, len$, j$, ref1$, len1$, y; for (i$ = 0; i$ <= 10; i$ += 2) { x = i$; if (x !== 4) { x + 1; } } for (i$ = 0, len$ = (ref$ = ['a', 'b']).length; i$ < len$; ++i$) { x = ref$[i$]; for (j$ = 0, len1$ = (ref1$ = [1, 2]).length; j$ < len1$; ++j$) { y = ref1$[j$]; x + "" + y; } }
Vous pouvez formater vos compréhensions avec de l'identation :
[{id:id1, name, age} for {id:id1, name} in table1 for {id:id2, age} in table2 when id1 is id2]
var i$, ref$, len$, ref1$, id1, name, j$, len1$, ref2$, id2, age; for (i$ = 0, len$ = (ref$ = table1).length; i$ < len$; ++i$) { ref1$ = ref$[i$], id1 = ref1$.id, name = ref1$.name; for (j$ = 0, len1$ = (ref1$ = table2).length; j$ < len1$; ++j$) { ref2$ = ref1$[j$], id2 = ref2$.id, age = ref2$.age; if (id1 === id2) { ({ id: id1, name: name, age: age }); } } }
Les compréhensions d'objets renvoient des objets :
{[key, val * 2] for key, val of {a: 1, b: 2}} #=> {a: 2, b: 4}
var key, ref$, val; for (key in ref$ = { a: 1, b: 2 }) { val = ref$[key]; [key, val * 2]; }
Boucles while
:
i = 0 list = [1 to 10] while n < 9 n = list[++i]
var i, list, n; i = 0; list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; while (n < 9) { n = list[++i]; }
until
est l'équivalent de while not
.
while
/until
acceptent aussi une clause when
, guard optionnel, else
ainsi qu'un block else
si la boucle n'a pas été évalué.
i = 1 list = [1 to 10] until i > 7 when n isnt 99 n = list[++i] else 10
var i, list, yet$, n; i = 1; list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (yet$ = true; !(i > 7);) { yet$ = false; if (n !== 99) { n = list[++i]; } } if (yet$) { 10; }
do while
:
i = 0 list = [1 to 10] do i++ while list[i] < 9
var i, list; i = 0; list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; do { i++; } while (list[i] < 9);
while
accepte aussi une clause exécutée à chaque itération.
i = 0 list = [1 to 10] while list[i] < 9, i++ then i
var i, list; i = 0; list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (; list[i] < 9; i++) { i; }
while true
:
i = 0 loop \ha break if ++i > 20 i = 0 for ever \ha if ++i > 20 break
var i; i = 0; for (;;) { 'ha'; if (++i > 20) { break; } } i = 0; for (;;) { 'ha'; if (++i > 20) { break; } }
break
est automatiquement inséré, et les conditions multiples sont autorisées :
switch 6 case 1 then \hello case 2, 4 then \boom case 6 'here it is' default \something
switch (6) { case 1: 'hello'; break; case 2: case 4: 'boom'; break; case 6: 'here it is'; break; default: 'something'; }
Si vous ne donnez pas d'opérance à switch
, ce sera true
. (le code compile à switch (false)
pour permettre une conversion booléenne via un unique !
plutôt que !!
)
switch case 5 == 6 \never case false 'also never' case 6 / 2 is 3 'here'
switch (false) { case 5 !== 6: 'never'; break; case !false: 'also never'; break; case 6 / 2 !== 3: 'here'; }
Vous pouvez utiliser fallthrough
pour empêcher l'insertion d'un break
implicite, et doit être la dernière expression du case
. Aussi, vous pouvez utiliser un switch
en tant qu'expression :
result = switch 6 case 6 something = 5 fallthrough case 4 'this is it' result #=> 'this is it'
var result, something; result = (function(){ switch (6) { case 6: something = 5; // fallthrough case 4: return 'this is it'; } }()); result;
|
est un alias pour case
, et =>
est un alias pour then
. | otherwise
et | _
sont des alias pour default
:
switch 'moto' | "quelque chose" => \coucou | \explosion \bomb => \boom | <[ la moto ? ]> => 'ici !' | otherwise => \quelquechose
switch ('moto') { case "quelque chose": 'coucou'; break; case 'explosion': case 'bomb': 'boom'; break; case 'la': case 'moto': case '?': 'ici !'; break; default: 'quelquechose'; }
Un switch
implicite est ajouté après les flèches (comme ->
), :
, et =
si un case
(ou |
) est trouvé :
func = (param) -> | param.length < 5 => param.length | otherwise => param.slice 3 func 'coucou' #=> cou state = | 2 + 2 is 5 => "I love Big Brother" | _ => "I love Julia"
var func, state; func = function(param){ switch (false) { case !(param.length < 5): return param.length; default: return param.slice(3); } }; func('coucou'); state = (function(){ switch (false) { case 2 + 2 !== 5: return "I love Big Brother"; default: return "I love Julia"; } }());
Vous pouvez aussi utiliser les switch
de CoffeeScript.
day = \Sum switch day when "Lun" then 'Au boulot' when "Mar" then 'Au ciné' when "Mer" then 'Au café' when "Ven", "Sam" 'Au bingo' when "Dim" then 'Toujours au café' else 'Au boulot'
var day; day = 'Sum'; switch (day) { case "Lun": 'Au boulot'; break; case "Mar": 'Au ciné'; break; case "Mer": 'Au café'; break; case "Ven": case "Sam": 'Au bingo'; break; case "Dim": 'Toujours au café'; break; default: 'Au boulot'; }
L'assignement basique est comme vous vous y attendez, variable = value
, et il n'y a pas besoin de déclarer les variables. Cependant, contrairement à CoffeeScript, vous devez utiliser :=
pour modifier les variables dans des portées supérieures.
x = 10 do -> x = 5 x #=> 10 do -> x := 2 x #=> 2
var x; x = 10; (function(){ var x; return x = 5; })(); x; (function(){ return x = 2; })(); x;
Presque tout est une expression, ce qui signifie que vous pouvez faire des choses comme :
x = if 2 + 2 == 4 then 10 else 0 x #=> 10
var x; x = 2 + 2 === 4 ? 10 : 0; x;
Même les boucles, switch, voire les try/catch sont des expressions.
Si vous voulez simplement déclarer une variable sans l'initialiser, utilisez var
.
var x
var x;
Vous pouvez aussi déclarer des constantes avec le mot-clef const
. Les vérifications sont faites à la compilation — le JavaScript compilé est le même.
Essayer de compiler le code suivant :
const x = 10 x = 0
Donnera l'erreur suivante : redeclaration of constant "x" on line 2
(re-déclaration de la constante "x" ligne 2).
À l'inverse, les objets ne sont pas "gêlés" — vous pouvez quand même modifier leurs propriétés. Vous pouvez forcer toutes les variables à être des constantes à l'aide de l'option -k
(ou --const
).
Results in redeclaration of constant "x" on line 2
.
Assignation composée :
(?
, ||
, or &&
peuvent préfixer n'importe quelle assignation.)
x = 2 #=> 2 x += 2 #=> 4 x -= 1 #=> 3 x *= 3 #=> 9 x /= 3 #=> 3 x %= 3 #=> 0 x %%= 3 #=> 0 x <?= -1 #=> -1 x >?= 2 #=> 2 x **= 2 #=> 4 x ^= 2 #=> 16 x ?= 10 x #=> 16 x ||= 5 #=> 16 x &&= 5 #=> 5 x &&+= 3 #=> 8 x ?*= 2 #=> 16 xs = [1 2] xs ++= [3] xs #=> [1 2 3]
var x, ref$, xs; x = 2; x += 2; x -= 1; x *= 3; x /= 3; x %= 3; x = ((x) % (ref$ = 3) + ref$) % ref$; x <= (ref$ = -1) || (x = ref$); x >= 2 || (x = 2); x = Math.pow(x, 2); x = Math.pow(x, 2); x == null && (x = 10); x; x || (x = 5); x && (x = 5); x && (x += 3); x != null && (x *= 2); xs = [1, 2]; xs = xs.concat([3]); xs;
Assignation unaire :
y = \45 + = y #=> 45 (conversion en nombre) !! = y #=> true (conversion en booléen) -~-~ = y #=> 3 (conversion en entier doublement incrémentale)
var y; y = '45'; y = +y; y = !!y; y = -~-~y;
Valeurs par défaut — vous pouvez utiliser ||
, &&
et ?
.
Vous pouvez utiliser =
à la place de ?
dans les paramètres et les destructurations :
x ? y = 10 y #=> 10 f = (z = 7) -> z f 9 #=> 9 f! #=> 7
var y, f; (typeof x == 'undefined' || x === null) && (y = 10); y; f = function(z){ z == null && (z = 7); return z; }; f(9); f();
Assignation conditionnelle — n'assigne que si l'opérande de droite existe :
age = 21 x? = age x #=> 21 x? = years x #=> 21
var age, x; age = 21; if (age != null) { x = age; } x; if (typeof years != 'undefined' && years !== null) { x = years; } x;
La déstructuration est une manière puissante d'extraire des valeurs depuis des listes et des objets, vous permettant de lire directement des structures :
[first, second] = [1, 2] first #=> 1 second #=> 2
var ref$, first, second; ref$ = [1, 2], first = ref$[0], second = ref$[1]; first; second;
Vous pouvez aussi obtenir la partie restante :
[head, ...tail] = [1 to 5] head #=> 1 tail #=> [2,3,4,5] [first, ...middle, last] = [1 to 5] first #=> 1 middle #=> [2,3,4] last #=> 5
var ref$, head, tail, first, i$, middle, last, slice$ = [].slice; ref$ = [1, 2, 3, 4, 5], head = ref$[0], tail = slice$.call(ref$, 1); head; tail; ref$ = [1, 2, 3, 4, 5], first = ref$[0], middle = 1 < (i$ = ref$.length - 1) ? slice$.call(ref$, 1, i$) : (i$ = 1, []), last = ref$[i$]; first; middle; last;
La déstructuration marche aussi avec les objets :
{name, age} = {weight: 110, name: 'emma', age: 20} name #=> 'emma' age #=> 20
var ref$, name, age; ref$ = { weight: 110, name: 'emma', age: 20 }, name = ref$.name, age = ref$.age; name; age;
Vous pouvez aussi labeller les structures avec :label
, ou imbriquer les déstructurations :
[[x, ...xs]:list1, [y, ...ys]:list2] = [[1,2,3],[4,5,6]] x #=> 1 xs #=> [2,3] list1 #=> [1,2,3] y #=> 4 ys #=> [5,6] list2 #=> [4,5,6]
var ref$, list1, x, xs, list2, y, ys, slice$ = [].slice; ref$ = [[1, 2, 3], [4, 5, 6]], list1 = ref$[0], x = list1[0], xs = slice$.call(list1, 1), list2 = ref$[1], y = list2[0], ys = slice$.call(list2, 1); x; xs; list1; y; ys; list2;
Permet de lire et écrire aisément les propriétés d'objets :
mitch = age: 21 height: 180cm pets: [\dog, \goldfish] phile = {} phile{height, pets} = mitch phile.height #=> 180 phile.pets #=> ['dog', 'goldfish']
var mitch, phile; mitch = { age: 21, height: 180, pets: ['dog', 'goldfish'] }; phile = {}; phile.height = mitch.height, phile.pets = mitch.pets; phile.height; phile.pets;
Le standard :
[1 2 3][1] #=> 2 {a: 1, b: 2}.b #=> 2
[1, 2, 3][1]; ({ a: 1, b: 2 }).b;
L'accès avec un point — le point accepte bien plus qu'un simple identifieur comme opérande de droite, vous pouvez aussi donner des nombres, chaînes, parenthèses, etc :
x = "hello world": [4 [5 boom: 6]] x.'hello world'.1.[0] #=> 5
var x; x = { "hello world": [ 4, [ 5, { boom: 6 } ] ] }; x['hello world'][1][0];
Accessignation avec .=
.
document.title .= to-upper-case! #=> LIVESCRIPT ...
document.title = document.title.toUpperCase();
Récupérer ou assigner une partie de liste :
list = [1 2 3 4 5] list[2, 4] #=> [3,5] list[1 to 3] #=> [2,3,4] list[1 til 3] #=> [2,3] list[1 til 3] = [7 8] list #=> [1,7,8,4,5]
var list, ref$; list = [1, 2, 3, 4, 5]; [list[2], list[4]]; [list[1], list[2], list[3]]; [list[1], list[2]]; ref$ = [7, 8], list[1] = ref$[0], list[2] = ref$[1]; list;
Une partie d'un objet :
obj = one: 1, two: 2 obj{first: one, two} #=> {first: 1, two: 2}
var obj; obj = { one: 1, two: 2 }; ({ first: obj.one, two: obj.two });
L'étoile de longueur *
.
list = [1 2 3 4 5] list[*] = 6 list #=> [1,2,3,4,5,6] list[*-1] #=> 6
var list; list = [1, 2, 3, 4, 5]; list[list.length] = 6; list; list[list.length - 1];
Semi-autovivification .{}
(objet), .[]
(liste) permet de s'assurer que la propriété est un objet ou une liste :
x = "hello world": [4 [5 boom: 6]] x.[]'hello world'.1.{}1.boom #=> 6 x.[]arr.{}1.y = 9 x.arr.1.y #=> 9
var x, ref$; x = { "hello world": [ 4, [ 5, { boom: 6 } ] ] }; ((ref$ = (x['hello world'] || (x['hello world'] = []))[1])[1] || (ref$[1] = {})).boom; ((ref$ = x.arr || (x.arr = []))[1] || (ref$[1] = {})).y = 9; x.arr[1].y;
L'accès lié .~
récupère une méthode d'un objet en la liant à cet objet. Avec l'auto-insertion de points, vous pouvez simplement utiliser ~
.
obj = x: 5 add: (y) -> @x + y target = x: 600 not-bound: obj.add bound: obj~add target.not-bound 5 #=> 605 target.bound 5 #=> 10
var obj, target; obj = { x: 5, add: function(y){ return this.x + y; } }; target = { x: 600, notBound: obj.add, bound: bind$(obj, 'add') }; target.notBound(5); target.bound(5); function bind$(obj, key, target){ return function(){ return (target || obj)[key].apply(obj, arguments) }; }
Une cascade retourne l'objet accédé, et non pas les opérations
Enchaînement via cascades :
a = [2 7 1 8] ..push 3 ..shift! ..sort! a #=> [1,3,7,8] document.query-selector \h1 ..style ..color = \red ..font-size = \large ..inner-HTML = 'LIVESCRIPT!'
var x$, a, y$, z$; x$ = a = [2, 7, 1, 8]; x$.push(3); x$.shift(); x$.sort(); a; y$ = document.querySelector('h1'); z$ = y$.style; z$.color = 'red'; z$.fontSize = 'large'; y$.innerHTML = 'LIVESCRIPT!';
Les cascades sont appellables, et peuvent contenir n'importe quel code :
console.log x = 1 y = 2 .. x, y # affiche `1 2` dans la console
var x$, x, y; x$ = console.log; x = 1; y = 2; x$(x, y);
Vous pouvez utiliser with
pour effectuer la cascade avant l'assignation :
x = with {a: 1, b: 2} ..a = 7 ..b += 9 x #=> {a: 7, b: 11}
var x, x$; x = (x$ = { a: 1, b: 2 }, x$.a = 7, x$.b += 9, x$); x;
Vous pouvez lancer des exceptions avec throw
.
throw new Error 'Une erreur est survenue !'
throw new Error('Une erreur est survenue !');
Vous pouvez attraper les exceptions avec try
, catch
, finally
. Les blocs catch
et finally
sont optionnels.
Le bloc try
est éxecuté. Si une exception est lancée, le bloc catch
est éxecuté, avec l'objet. Contrairement au JavaScript, l'exception est liée à la portée de la fonction la plus proche, non pas au bloc catch
. Vous pouvez même déstructurer l'exception si vous le voulez :
try ... try ... catch 2 + 2 e.message x = try ... catch {message} message x #=> unimplemented
var e, x, message; try { throw Error('unimplemented'); } catch (e$) {} try { throw Error('unimplemented'); } catch (e$) { e = e$; 2 + 2; } e.message; x = (function(){ try { throw Error('unimplemented'); } catch (e$) { message = e$.message; return message; } }()); x;
Le bloc finally
est éxecuté après le bloc try
ou le bloc catch
, peu importe qu'il y ait eu une exception ou non.
try ... catch handle-exception e finally do-something! try ... finally do-something!
var e; try { throw Error('unimplemented'); } catch (e$) { e = e$; handleException(e); } finally { doSomething(); } try { throw Error('unimplemented'); } finally { doSomething(); }
Les classes sont simplement une syntaxe offerte pour définir un constructeur et les fonctions du prototype.
Le constructeur est une fonction déclarée directement dans la classe.
Les propriétés du prototypes sont définies avec la même syntaxe que les objets.
class A (num) -> @x = num property: 1 method: (y) -> @x + @property + y a = new A 3 a.x #-> 3 a.property #=> 1 a.method 6 #=> 10
var A, a; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; function A(num){ this.x = num; } A.prototype.property = 1; A.prototype.method = function(y){ return this.x + this.property + y; }; return A; }()); a = new A(3); a.x; a.property; a.method(6);
Les propriétés statiques (attachées au constructeur) sont définies en préfixant le nom de la propriété par un this
(ou @
). Ces propriétés peuvent être accédées via le constructor
(ou @@
) :
class A @static-prop = 10 get-static: -> @@static-prop + 2 A.static-prop #=> 10 a = new A a.get-static! #=> 12
var A, a; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; A.staticProp = 10; A.prototype.getStatic = function(){ return constructor.staticProp + 2; }; function A(){} return A; }()); A.staticProp; a = new A; a.getStatic();
Les propriétés privées statiques sont juste définies comme des variables dans le bloc de la classe. (note : les propriétés privées pour une instance sont impossibles en JavaScript, et par conséquent, en LiveScript.)
class A secret = 10 get-secret: -> secret a = new A a.get-secret! #=> 10
var A, a; A = (function(){ A.displayName = 'A'; var secret, prototype = A.prototype, constructor = A; secret = 10; A.prototype.getSecret = function(){ return secret; }; function A(){} return A; }()); a = new A; a.getSecret();
Vous pouvez définir des méthodes liées (using ~>
, qui auront alors leur this
lié à l'instance :
class A x: 10 bound-func: (x) ~> @x reg-func: (x) -> @x a = new A obj = x: 1 bound: a.bound-func reg: a.reg-func obj.bound! #=> 10 obj.reg! #=> 1
var A, a, obj; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; A.prototype.x = 10; A.prototype.boundFunc = function(x){ return this.x; }; A.prototype.regFunc = function(x){ return this.x; }; function A(){ this.boundFunc = bind$(this, 'boundFunc', prototype); } return A; }()); a = new A; obj = { x: 1, bound: a.boundFunc, reg: a.regFunc }; obj.bound(); obj.reg(); function bind$(obj, key, target){ return function(){ return (target || obj)[key].apply(obj, arguments) }; }
Vous pouvez facilement modifier les propriétés dans les fonctions et dans le constructeur via le raccourci depuis les paramètres :
class A (@x) -> f: (@y) -> @x + @y a = new A 2 a.x #=> 2 a.f 3 #=> 5 a.y #=> 3
var A, a; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; function A(x){ this.x = x; } A.prototype.f = function(y){ this.y = y; return this.x + this.y; }; return A; }()); a = new A(2); a.x; a.f(3); a.y;
Si vous définissez le constructeur en tant que fonction liée (~>
), vous n'aurez pas besoin d'utiliser new
pour l'instanciation :
class A (@x) ~> a = A 4 a.x #=> 4
var A, a; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; function A(x){ var this$ = this instanceof ctor$ ? this : new ctor$; this$.x = x; return this$; } function ctor$(){} ctor$.prototype = prototype; return A; }()); a = A(4); a.x;
Pour les bibliothèques haut niveau et autres, vous pouvez assigner le constructeur à une fonction externe, en assignant constructor$$
. Ce n'est pas recommandé cependant.
f = (@x) -> class A constructor$$: f a = new A 5 a.x #=> 5
var f, A, a; f = function(x){ this.x = x; }; A = (function(){ A.displayName = 'A'; var constructor$$, prototype = A.prototype, constructor = A; function A(){ return constructor$$.apply(this, arguments); } constructor$$ = f; return A; }()); a = new A(5); a.x;
Vous pouvez hériter avec extends
:
class A -> @x = 1 @static-prop = 8 method: -> @x + 2 class B extends A -> @x = 10 B.static-prop #=> 8 b = new B b.x #=> 10 b.method! #=> 12
var A, B, b; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; function A(){ this.x = 1; } A.staticProp = 8; A.prototype.method = function(){ return this.x + 2; }; return A; }()); B = (function(superclass){ var prototype = extend$((import$(B, superclass).displayName = 'B', B), superclass).prototype, constructor = B; function B(){ this.x = 10; } return B; }(A)); B.staticProp; b = new B; b.x; b.method(); function extend$(sub, sup){ function fun(){} fun.prototype = (sub.superclass = sup).prototype; (sub.prototype = new fun).constructor = sub; if (typeof sup.extended == 'function') sup.extended(sub); return sub; } function import$(obj, src){ var own = {}.hasOwnProperty; for (var key in src) if (own.call(src, key)) obj[key] = src[key]; return obj; }
Vous pouvez utiliser avec super
. Si seul, super
est une référence à la fonction appropriée. Si vous voulez l'appeler en passant les arguments, utilisez super ...
.
class A -> @x = 1 method: (num) -> @x + num class B extends A -> @y = 2 super! method: (num) -> @y + super ... b = new B b.y #=> 2 b.method 10 #=> 13
var A, B, b; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; function A(){ this.x = 1; } A.prototype.method = function(num){ return this.x + num; }; return A; }()); B = (function(superclass){ var prototype = extend$((import$(B, superclass).displayName = 'B', B), superclass).prototype, constructor = B; function B(){ this.y = 2; B.superclass.call(this); } B.prototype.method = function(num){ return this.y + superclass.prototype.method.apply(this, arguments); }; return B; }(A)); b = new B; b.y; b.method(10); function extend$(sub, sup){ function fun(){} fun.prototype = (sub.superclass = sup).prototype; (sub.prototype = new fun).constructor = sub; if (typeof sup.extended == 'function') sup.extended(sub); return sub; } function import$(obj, src){ var own = {}.hasOwnProperty; for (var key in src) if (own.call(src, key)) obj[key] = src[key]; return obj; }
Vous pouvez utiliser des mixins via implements
. Vous ne pouvez hériter que d'une classe, mais vous pouvez avoir autant de mixins que vous le voulez.
Souvenez-vous, si vous voulez implémenter une classe et non un simple objet, vous devrez implémenter son prototype.
Renameable = set-name: (@name) -> get-name: -> @name ? @id class A implements Renameable -> @id = Math.random! * 1000 a = new A a.get-name! #=> some random number a.set-name 'moo' a.get-name! #=> 'moo'
var Renameable, A, a; Renameable = { setName: function(name){ this.name = name; }, getName: function(){ var ref$; return (ref$ = this.name) != null ? ref$ : this.id; } }; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; importAll$(prototype, arguments[0]); function A(){ this.id = Math.random() * 1000; } return A; }(Renameable)); a = new A; a.getName(); a.setName('moo'); a.getName(); function importAll$(obj, src){ for (var key in src) obj[key] = src[key]; return obj; }
Pour modifier le prototype, vous pouvez utiliser le raccourci ::
, et vous pouvez utiliser ::=
pour modifier plusieurs propriétés :
class A prop: 10 f: -> @prop a = new A b = new A a.f! #=> 10 A::prop = 6 a.f! #=> 6 b.f! #=> 6 A ::= prop: 5 f: -> @prop + 4 a.f! #=> 9 b.f! #=> 9
var A, a, b, ref$; A = (function(){ A.displayName = 'A'; var prototype = A.prototype, constructor = A; A.prototype.prop = 10; A.prototype.f = function(){ return this.prop; }; function A(){} return A; }()); a = new A; b = new A; a.f(); A.prototype.prop = 6; a.f(); b.f(); ref$ = A.prototype; ref$.prop = 5; ref$.f = function(){ return this.prop + 4; }; a.f(); b.f();
Si vous ne souhaitez pas supporter les anciens navigateurs et voulez utiliser Object.defineProperty
, la syntaxe suivante est à votre disposition :
class Box dimensions:~ -> @d ([width, height]) -> @d = "#{width}x#height" b = new Box b.dimensions = [10 5] b.dimensions #=> '10x5'
var Box, b; Box = (function(){ Box.displayName = 'Box'; var prototype = Box.prototype, constructor = Box; Object.defineProperty(Box.prototype, 'dimensions', { get: function(){ return this.d; }, set: function(arg$){ var width, height; width = arg$[0], height = arg$[1]; this.d = width + "x" + height; }, configurable: true, enumerable: true }); function Box(){} return Box; }()); b = new Box; b.dimensions = [10, 5]; b.dimensions;
=>
pour des flèches ondulées ~>
### ###
pour /* */
[x..y]
pour [x to y]
et changez [x...y]
en [x til y]
. Si votre série descend, et que ce n'est pas évident (le from et le to ne sont pas littéraux), vous devez ajouter by -1
, par exemple [x to -3 by -1]
for
utilisant la syntaxe for i in [x..y]
pour for i from x to y
, de même pour for i in [x...y]
à transformer en for i from x til y
(x for x in list)
pour [x for x in list]
. Toutes les boucles suffixes qui ne doivent pas retourner des listes ne doivent pas être en suffixes, par exemple, changez increase x for x in list
pour for x in list then increase x
. Vous pouvez économiser des caractères en utilisant l'alias de then
, la flèche doublée =>
.5
en ajoutant un zéro 0.5
/// ///
vers // //
...
) est en préfixe, non pas en suffixe ((...args) ->
)
() ->
doit être ->
— ()
est toujours un appel.
class Item constructor: ->Pour :
class Item ->Si votre constructeur est une fonction externe, assignez
constructor$$
.
super
à) super ...
— super
est une référence directe à la fonction parente et non pas un appel.
&
est .&.
et >>
est .>>.
(etc)
x = 10 do -> x = 5vous douvez utiliser l'opérateur
:=
au lieu du simple =
car ce dernier est toujours utilisé pour déclarer une variable (shadowing). Le code ci-dessus devrait être
x = 10 do -> x := 5
it
, that
, fallthrough
, ou otherwise
pour vos variables. Cela peut ne pas être techniquement requis dans tous les cas, mais sera moins confus. Référez-vous à la documentation ci-dessus pour leurs utilisations.
"string"
ou 'string'
)
text = "hi there"devra être changé car produit, en CoffeeScript,
"hi there"
mais "hi there"
en LiveScript.
and
, or
et les versions espacées de .
and ?.
ferment les appels implicites : f a .g b or h c
est f(a.g(b || h(c)))
in CoffeeScript and f(a).g(b) || h(c)
in LiveScript. You can use ||
instead of or
and &&
instead of and
as those versions do not close implicit calls.
do
s-bloc pour utiliser let
. Par exemple : en CoffeScript do ($ = jQuery) -> $
à changer pour
let $ = jQuery $
do
pour les appels implicites suivis d'un bloc :
f a: bà transformer en
f do a: b
`js code here`
pour ``js code here``
x . y
), c'est l'opérateur de composition de fonctions en LiveScript
a-b
pour a - b
. a-1
et 1-b
sont toujours valides (mais déconseillés), car a-b
est un identifieur valide en LiveScript, qui se compile en camelCase : aB
.
Vous pouvez trouver la liste des contributeurs ici. Cette liste inclue aussi les contributeurs aux précédesseurs.
Les personnes qui ont contribuées directement, incluant George Zahariev, Satoshi Murakami, Joshua Weinstein, Josh Perez, et Paul Miller.
Un remerciement spécial pour Satoshi car ce projet est un dérivé de son langage Coco et ne serait possible sans.
Traduction par Vendethiel.
Créez un fork de LiveScript et effectuez vos modifications, sans oublier les tests (dossier /test
).
Éxecutez bin/slake
pour voir les commandes disponibles. Assurez-vous de pouvoir lancer bin/slake build:full
— à savoir, recompiler le compilateur. Utile : git checkout -- lib && bin/slake build:full
: nettoie votre lib
et compile ainsi que lance vos tests. N'envoyez une Pull Request que si tous vos tests passant. Si vous modifiez la grammaire, vous devrez lancer git checkout -- lib && bin/slake build && bin/slake build:parser && bin/slake test
. Une fois que tous les tests sont passés, modifiez les parties du compilateur à modifier, puis éxecutez bin/slake build:full
.
Ne recompilez pas (extras/livescript.js
) (créé par bin/slake build:browser
). Ce fichier n'est regénéré que lors de nouvelles versions.