CoffeeScript: nový jazyk, nové chytáky

CoffeeScript vzbudil mezi vývojáři webových aplikací slušný zájem, mnozí si pochvalují jeho vyjadřovací schopnosti a eleganci. Přesto má CoffeeScript, jako každý jazyk, kromě příjemných překvapení i některé záludnosti a tajemná zákoutí, do nichž může nepřipravený vývojář snadno padnout.

CoffeeScript je velmi mladý jazyk. Vývojářům ještě nenabízí vyspělý ekosystém (například debuggery), ani s literaturou to není tak úplně slavné a vědění se šíří zatím převážně v diskusních fórech a na Twitteru. První skutečná kniha, která vyšla na téma CoffeeScript, byla vydána nakladatelstvím Pragmatic Programmers, jmenuje se CoffeeScript: Accelerated JavaScript Development a autorem je Trevor Burnham.

V této knize naleznete nejen informace o programování v CoffeeScriptu či praktické rady (jak instalovat, jak debuggovat, kde nalézt vhodné pluginy pro editory), ale i upozornění na některá úskalí, která CoffeeScript (potažmo JavaScript) přináší, stejně jako tipy a triky, které vám používání CoffeeScriptu zpříjemní. V dalším textu se na některá taková tajemství, probíraná ve zmíněné knize, podíváme.

Když na mezeře záleží…

Z většiny programovacích jazyků jsme zvyklí, že na nějaké té mezeře většinou nezáleží. V JavaScriptu například není rozdíl mezi těmito dvěma zápisy:

var prefix = "#prvek_";
// zápis 1
var id1 = prefix + 12;
// zápis 2 - jedna mezera chybí
var id2 = prefix +12;

V CoffeeScriptu bude rozdíl významný:

prefix = "#prvek_"
id1 = prefix + 12 # == #prvek_12
id2 = prefix +12 # TypeError

Proč? Vzpomeňme na to, že Coffeescript umožňuje zapsat volání funkcí bez závorek. Poslední řádek tak bude přeložen jako

var id2 = prefix(+12);

což je něco jiného, než jsme zamýšleli.

Stejně tak může problémy způsobit fakt, že toto vyhodnocování operátorů je asociativní zprava, takže konstrukce

console.log (fn 3, fn 4)

vypíše pouze výsledek volání funkce fn(3). Kompiler totiž vyhodnotí zápis jako:

console.log (fn (3, fn (4)))

tedy zase opět něco zcela jiného.

Doporučení: parametry vnořených volání funkcí pište do závorek; vynechat je můžete pouze u volání nejvyšší úrovně. Tedy:  console.log fn(3), fn(4).

Pozor na mezeru mezi jménem funkce a závorkou: console.log fn (3), fn (4) bude vyhodnocena opět jinak – tím výše zmíněným způsobem, tedy jako vnořené volání funkce fn!

Scope – oblast viditelnosti

Záhadné chyby může způsobit implicitní pravidlo oboru platnosti proměnných. Proměnné se v Coffeescriptu nedefinují explicitně, ale využívají se tři pravidla:

  1. Funkce vytváří oblast viditelnosti (scope), a jediný způsob, jak vytvořit oblast viditelnosti, je definice funkce.
  2. Proměnná je viditelná v oblasti nejvyšší úrovně, kde jí byla přiřazena hodnota.
  3. Mimo scope není proměnná viditelná.

Jak ukazuje Trevor Burnham v kapitole 2.2, přináší to někdy podivuhodné konsekvence:

x = 42
init = -> x = 0
init()
console.log x

Výsledek bude nula, protože definice funkce na řádku 2 vyhodnotí x jako globální proměnnou (resp. existující v nadřazeném scope). Co způsobí prohození řádků 1 a 2?

init = -> x = 0
x = 42
init()
console.log x

Tentokrát bude výsledek 42, protože v okamžiku definice funkce (na řádku 1) bude x neznámé, a bude vyhodnoceno tedy jako lokální proměnná viditelná pouze ve funkci init.

Je to logické a vyplývá to z pravidel viditelnosti proměnných v CoffeeScriptu, přesto to dokáže zaskočit. A aby nebylo zmatků dost: pokud má funkce parametr, pojmenovaný stejně jako „globální“ proměnná (správně: jako proměnná v nadřazeném scope), bude v těle funkce rovněž lokální. Upravíme první příklad:

x = 42
triple = (x) -> x * 3
console.log triple x
console.log x

V těle funkce triple bude proměnná x tentokrát lokální!

== a ===

V JavaScriptu je zásadní rozdíl mezi operátory == a ===. Viz lehce upravený příklad z WTFJS:

var a = 0, b = '', c = '0';
a == b; // true
a == c; // true
b == c; // false

Matematik by řekl, že operátor == není tranzitivní. CoffeeScript v tomto ohledu lehce programátorovi pomůže: pokud zapíšete ==, přeloží ho jako ===. Jak v CoffeeScriptu ale zapíšete ekvivalent JS operátoru ==? Odpověď: Nijak. Vždy se porovnává typově.

key:value

Představme si definici objektu:

x = 10
y = 20
radius = 5
kruh = {x: x, y: y, radius: radius}

CoffeeScript má pro případy, kdy se vlastnost jmenuje stejně jako proměnná, která je přiřazována, zkratku. Poslední řádek lze tedy zapsat i takto:

kruh = {x, y, radius}

Ovšem CoffeeScript jde ještě o kousek dál. Vzpomínáte na „destrukturované přiřazení“?

pole = [10, 20]
[a, b] = pole

Stejným způsobem lze přiřadit i vlastnosti objektů:

{x: mojeX, y: mojeY} = kruh

A opět: pokud se vlastnost jmenuje stejně jako proměnná, do níž bude přiřazováno, lze zkrátit:

{x, y} = kruh

Autor uvádí i příklad při vývoji pro Node.js – píšete testy a potřebujete metody assert.ok a assert.strictEqual. Můžete použít konstrukci:

{ok, strictEqual} = require "assert"

a budete mít obě metody dostupné v proměnných ok a strictEqual.

Destrukturované přiřazení lze zapsat i vnořené – parsování dat v JSON je pak lahůdka:

{result: [code, text]} = serverResponse

Když super() není super

CoffeeScript usnadňuje i psaní tříd „běžným“ způsobem (a odstiňuje tak programátora od zapeklitostí prototypové dědičnosti). K volání metod předka pak používá obvyklé volání metody super().

class Vyrobek
  constructor: (zaruka) ->
    DBzaruk.save(this) if zaruka
     
class Toaster extends Vyrobek
  constructor: (zaruka) ->
    super()

V takovémhle případě je volání metody rodičovské třídy chybně – nepředáme parametr zaruka. Můžeme napsat super(zaruka), ale CoffeeScript má (opět) pohodlnější zkratku:

class Toaster extends Vyrobek
  constructor: (zaruka) ->
    super

Takto zapsáno zavolá stejnojmennou metodu rodičovské třídy se všemi parametry.

A dál…?

CoffeeScript představuje pro vývojáře novou neprobádanou oblast, kde je možné za každým rohem narazit na zajímavou možnost, která vám ulehčí práci – ovšem taky můžete narazit i v místech, kde si jste jistí, že přesně víte, co děláte. Doufejme, že tento článek alespoň trochu osvětlil některá potenciálně nebezpečná zákoutí a ušetřil vám krušné chvíle při ladění.

Začal programovat v roce 1984 s programovatelnou kalkulačkou. Pokračoval k BASICu, assembleru Z80, Forthu, Pascalu, Céčku, dalším assemblerům, před časem v PHP a teď by rád neprogramoval a radši se věnoval starým počítačům.

Komentáře: 19

Přehled komentářů

pepca Re: CoffeeScript: nový jazyk, nové chytáky
Jiří Knesl Re: CoffeeScript: nový jazyk, nové chytáky
Makovec Re: CoffeeScript: nový jazyk, nové chytáky
Jiří Knesl Re: CoffeeScript: nový jazyk, nové chytáky
Makovec Re: CoffeeScript: nový jazyk, nové chytáky
Jiří Knesl Re: CoffeeScript: nový jazyk, nové chytáky
Makovec Re: CoffeeScript: nový jazyk, nové chytáky
Dundee5 Re: CoffeeScript: nový jazyk, nové chytáky
Jiří Knesl Re: CoffeeScript: nový jazyk, nové chytáky
lopata Re: CoffeeScript: nový jazyk, nové chytáky
blizz Re: CoffeeScript: nový jazyk, nové chytáky
František Kučera Re: CoffeeScript: nový jazyk, nové chytáky
blizz Re: CoffeeScript: nový jazyk, nové chytáky
František Kučera Re: CoffeeScript: nový jazyk, nové chytáky
Čelo Re: CoffeeScript: nový jazyk, nové chytáky
alancox Strašný jazyk
srigi Re: Strašný jazyk
blizz Re: CoffeeScript: nový jazyk, nové chytáky
Jan Prachař Upřesnění
Zdroj: https://www.zdrojak.cz/?p=3545