Manual:Coding conventions/JavaScript/cs

Tato stránka popisuje kódovací konvence pro JavaScript v MediaWiki codebase. Viz také obecné konvence.

Odkazování
Jako náš nástroj pro kvalitu kódu používáme ESLint s přednastavením eslint-config-wikimedia pro kódování většiny našich stylů kódování a pravidel kvality kódu. Na stránce Integrations na eslint.org najdete mnoho textových editorů nebo IDE s pluginy, které poskytují živou zpětnou vazbu při psaní.



Konfigurace Linter
Chcete-li z analýzy vyloučit soubory nebo adresáře (např. knihovny třetích stran), můžete konfigurovat vzory ignorování v ESLint prostřednictvím souboru. Všimněte si, že  je ve výchozím nastavení vyloučen, takže většina repozitářů nemusí nastavovat žádná pravidla ignorování.

Každé repo potřebuje soubor  v kořenovém adresáři úložiště. Následuje příklad konfiguračního souboru ESLint:

Živé příklady viz .eslintrc.json v MediaWiki a VisualEditoru.

Nezapomeňte nastavit, abyste předešli nechtěnému "magickému dědění" konfigurací ESLint v nesouvisejících nadřazených adresářích, které jste vy nebo server CI mohli nastavit na disku (například mezi rozšířením MediaWiki a jádrem MediaWiki nebo mezi vaším projektovým adresářem a něčím v váš domovský adresář).

Přednastavení eslint-config-wikimedia poskytuje několik profilů, ze kterých si mohou projekty vybrat, jak uznají za vhodné, jako jsou různé jazykové příchutě nebo globální prostředí běhového prostředí. Například:


 * - pro kód prohlížeče a očekává podporu ES5
 * - pro kód prohlížeče, který používá ES6
 * - pro kód Node.js 10+ a očekává podporu ES2018
 * - mix pro testy QUnit

Měli byste očekávat použití více souborů  v repo pro nastavení různých environmentálních očekávání pro různé podadresáře. Tím je zajištěno, že nepoužijete náhodou metody  v kódu serveru, který očekáváte na serveru, nebo že v produkčním kódu neodkážete na QUnit. soubory v podadresářích automaticky dědí z konfigurace nadřazeného adresáře, takže musí obsahovat pouze věci, které jsou specifické pro daný adresář (example file).



Nepřetržitá integrace
Projektům se doporučuje, aby prosadily předávání ESLint tím, že do něj zahrnou svůj  skript pomocí příkazu "test" do. Více informací o tom najdete na Continuous integration/Entry points.

Pokud má váš projekt poměrně náročný testovací kanál, lze definovat skript  nebo dokonce   v , aby bylo snadné spouštět pouze ty z příkazového řádku během místního vývoje (abyste nemuseli otevírat každý soubor v editoru a/nebo čekat na CI).

Chcete-li odhalit další funkce příkazového řádku z ESLint (jako je lintování jednotlivých souborů mimo textový editor nebo použití funkce --fix), definujte "eslint" jako vlastní skript v package.json bez jakéhokoli argumentu. Poté jej můžete vyvolat z příkazového řádku následovně:

Mezery
Používáme následující konvence:


 * Odsazení s tabulátory.
 * Žádné mezery na konci.
 * Oddělení jednoho bloku logicky souvisejícího kódu od druhého pomocí prázdných řádků.
 * Jedna mezera na obou stranách binárních operátorů a operátorů přiřazení.
 * Klíčová slova následovaná " " (levá závorka) musí být oddělena jednou mezerou. To poskytuje vizuální rozlišení mezi klíčovými slovy a vyvoláním funkcí.
 * Mezi názvem funkce a levou závorkou seznamu argumentů by neměla být žádná mezera.
 * Uvnitř závorek (jako jsou příkazy if, volání funkcí a seznamy argumentů) by měla být jedna mezera.
 * Nepoužívejte operátory, jako by to byly funkce (například,  ,  ,  ,  , ..).

Tyto a další aspekty našeho průvodce stylem jsou vynuceny pomocí ESLint.



Délka řádku
Řádky by neměly být delší než 80–100 znaků. Pokud se příkaz nevejde na jeden řádek, rozdělte příkaz na více řádků. Pokračování prohlášení by mělo být odsazeno o jednu úroveň navíc.

Volání funkcí a objekty by měly být buď na jednom řádku, nebo rozděleny na více řádků s jedním řádkem pro každý segment. Vyvarujte se zavírání volání funkce nebo objektu v jiném odsazení, než je jeho otevření.

Struktura
Ve zkratce:

Uzavření
Pokud balíček modulů nelze nebo z jiného důvodu ještě není registrován pomocí, pak by jeho jednotlivé soubory JavaScriptu měly mít kolem kódu uzávěr na úrovni souboru. To dává kódu jeho vlastní rozsah a zabraňuje úniku proměnných z nebo do jiných souborů, včetně režimu ladění, a způsobem, který je srozumitelný pro statickou analýzu. Tento vzor je známý jako ihned vyvolaný funkční výraz (nebo "iffy").

U souborů balíčků to není potřeba, protože se spouštějí jako soubor "modul" spíše než soubor "script", který má přirozeně svůj vlastní lokální rozsah. ESLint by měl být také nakonfigurován odpovídajícím způsobem (nastavte, jako v tomto příkladu).

Prohlášení
Proměnné musí být deklarovány před použitím. Každé zadání musí být na samostatném řádku. Proměnné mohou být deklarovány blízko nebo při jejich prvním přiřazení.

Pokud kombinujete více přiřazení  v jednom příkazu, pak deklarace, které nepřiřazují hodnotu, by měly být uvedeny před přiřazením. Následující řádky by měly být odsazeny o další úroveň.

Funkce by měly být deklarovány před použitím. V těle funkce by deklarace funkcí měly následovat po deklaracích proměnných a před jakýmikoli hlavními příkazy.

Komentáře
Komentáře by měly být na samostatném řádku a měly by být nad kódem, který popisují.

V rámci komentáře by měla být úvodní syntaxe (např. lomítko-lomítko nebo lomítko-hvězda) oddělena od textu jednou mezerou a text by měl začínat velkým písmenem. Pokud je komentář platnou větou, měla by být na jejím konci umístěna tečka.

Používejte řádkové komentáře ve funkcích a dalších blocích kódu (včetně víceřádkových komentářů).

Používejte blokové komentáře pouze pro bloky dokumentace. To pomáhá udržovat konzistentní formátování vkládaných komentářů (např. ne některé jako bloky a některé jako víceřádkové komentáře nebo nutnost převádět z jednoho na druhý). Vyhnete se také matoucím dokumentačním enginům. Usnadňuje také deaktivaci částí kódu během vývoje pouhým posunutím zápisu koncového komentáře o několik řádků dolů, aniž by byl zkratován vloženým blokovým komentářem.

Buďte v komentářích liberální a nebojte se kvůli tomu velikosti souboru. Veškerý kód je před odesláním automaticky minimalizován o.



Komentáře k dokumentaci

 * Text v blocích volného tvaru by měl být velkými a malými písmeny (např. popis metod, parametrů, návratových hodnot atd.)
 * Věty začínejte velkým písmenem.
 * V popisu pokračujte na dalším řádku, odsazeném o jednu mezeru navíc.



Vygenerovaná dokumentace

 * V současné době přecházíme z JSDuck na, protože první je neudržovaný.

Níže uvedené bude aktualizováno, jakmile bude JSDoc přijato do jádra MediaWiki.

K vytvoření dokumentace použijte JSDuck (viz https://doc.wikimedia.org).

JSDuck je předinstalovaný v nových prostředích a ve WMF CI. Chcete-li jej nainstalovat do vlastního vývojářského prostředí, použijte k instalaci z RubyGems. Další informace naleznete na stránce průvodce.

Pro vygenerování dokumentace by měl být použit , jak je definováno v.

Nakonfigurujte JSDuck ve svém projektu pomocí souboru. Viz konfigurace JSDuck nebo zkontrolujte příklady pro MediaWiki.

Značky - tagy
Používáme následující anotace. Z důvodu konzistence by měly být použity v pořadí, jak jsou zde popsány. Viz dokumentace JSDuck, jak to funguje.

Typy
Primitivní typy a speciální hodnoty: boolean, číslo, řetězec, nedefinováno, null.

Vestavěné třídy: Object, Array, Function, Date, RegExp, Error.

Rovnost

 * Použijte operátory přísné rovnosti ( a  ) místo (volné) rovnosti (  a  ). Ten druhý dělá typ nátlaku.
 * Nepoužívejte Yodovy podmínky.



Kontroly typů

 * string:
 * number:
 * boolean:
 * Function:
 * null:
 * object:
 * Plain Object:
 * Array:
 * HTMLElement:
 * undefined:
 * Místní proměnné:
 * Vlastnosti:
 * Globální proměnné

Řetězce
Pro řetězcové literály používejte jednoduché uvozovky místo dvojitých. Pamatujte, že v JavaScriptu nejsou žádné "kouzelné uvozovky", tj.  a   fungují všude.

Chcete-li extrahovat část řetězce, použijte pro konzistenci metodu. Vyhněte se metodám  nebo , které jsou nadbytečné, snadno zaměnitelné a mohou mít neočekávané vedlejší účinky.

Export
Použijte globální hodnoty vystavené prohlížečem (například document, location, navigator) přímo a ne jako vlastnosti objektu window. To zvyšuje důvěru v kód prostřednictvím statické analýzy a může také umožňovat další funkce IDE. Kromě globálů prohlížeče jsou bezpečné k použití pouze,   a.

Vyhněte se vytváření nových globálních proměnných. Vyhněte se úpravám globálních prvků, které "nevlastní" váš kód. Například vestavěné globály, jako je String nebo Object, nesmí být rozšířeny o další obslužné metody a podobně by těmto globálům neměly být přiřazeny funkce související s OOjs nebo jQuery.

Chcete-li veřejně vystavit funkce pro opětovné použití, použijte  ze  anebo přiřaďte vlastnosti v rámci hierarchie , např. .

Všimněte si, že konfigurační proměnné vystavené MediaWiki musí být přístupné přes.

Prostředí
Úprava vestavěných prototypů, jako je, je považována za škodlivou. Toto není podporováno v kódu MediaWiki a pravděpodobně to povede k poškození nesouvisejících funkcí.

Pojmenovávání
Všechny proměnné musí být pojmenovány pomocí CamelCase začínající malým písmenem, nebo pokud proměnná představuje nějaký druh konstantní hodnoty, použijte velká písmena (s podtržítky pro oddělení).

Všechny funkce musí být pojmenovány pomocí CamelCase, obvykle začínající malým písmenem, pokud není funkce konstruktorem třídy, v takovém případě musí začínat velkým písmenem. Method functions are preferred to start with verb, e.g.  instead of "foo".

Zkratky
Jména, která obsahují zkratky, by měla zkratku považovat za normální slovo a podle potřeby používat pouze velké první písmeno. To platí i pro dvoupísmenné zkratky, například. Například  na rozdíl od "getHTMLAPISource".

jQuery
Odlište uzly DOM od objektů jQuery předponou proměnným znakem dolaru, pokud budou obsahovat objekt jQuery, např. . To pomáhá omezit chyby tam, kde podmínky používají nesprávné podmíněné kontroly, jako je  namísto. Tam, kde metody DOM často vracejí hodnotu null (což je nepravda), metody jQuery vracejí prázdný objekt kolekce (které jsou, stejně jako nativní pole a další objekty v JavaScriptu, pravdivé).

npm
Při publikování samostatného projektu na npmjs.org zvažte jeho publikování pod jmenným prostorem. Všimněte si, že některé samostatné projekty, které jsou zaměřeny na použití mimo komunitu Wikimedia a mají dostatečně jedinečný název, v současnosti používají název balíčku bez jmenných prostorů (např. "oojs" a "visualeditor"). T239742



Vytváření prvků
Chcete-li vytvořit prostý prvek, použijte jednoduchou syntaxi v konstruktoru jQuery:

Při vytváření prvků na základě názvu značky z proměnné (která může obsahovat libovolný html):

Only use when you need to parse HTML (as opposed to creating a plain element).

Sbírky
Různé typy kolekcí někdy vypadají podobně, ale mají odlišné chování a mělo by se s nimi tak zacházet. Tento zmatek je většinou způsoben tím, že pole v JavaScriptu vypadají hodně jako pole v jiných jazycích, ale ve skutečnosti jsou pouze rozšířením Object. Používáme následující konvence:

Nepoužívejte smyčku  k opakování přes pole (na rozdíl od prostého objektu), protože   bude mít za následek mnoho neočekávaných chování, včetně: Klíčů jako řetězců, nestabilního pořadí iterací, indexů může přeskakovat mezery, opakování může zahrnovat jiné nečíselné znaky vlastnosti.

Úložiště
Keys in localStorage and/or sessionStorage should be accessed via  or.

Klíče
Keys should start with  and use camel case and/or hyphens. Do not use underscores or other separators. Examples of real keys:



Beware that contrary to cookies via mw.cookie, there is no wiki prefix or cookie prefix added by default. If values must vary by wiki, you must manually include  as part of the key.

Hodnoty
Values must be strings. Beware that attempting to store other value types will silently cast to a string (e.g.  would become  ).

Space is limited. Use short and concise values over object structures where possible. A few example:


 * For boolean state (true/false, expanded/collapsed) use "1" or "0".
 * For values that are always numbers, store them as-is and cast with  on the way out (avoid  ).
 * For values that are always strings, store them as-is.
 * For lists of software-defined values, consider comma-separated or pipe-separated strings to reduce space and processing cost.
 * For lists of values that may be user-generated or are otherwise complex in nature, use JSON.



Strategie vystěhování
Remember that Local storage does not have any eviction strategy by default. Therefore the following should be avoided:


 * Avoid using user-generated input as part of a key name.
 * Avoid keys containing identifiers for user-generated entities (e.g. user names, category names, page ids, or other user-provided or system-provided variables).
 * In general avoid approaches that involve creating a potentially large number of storage keys.

For example, if a feature needs to store state about a variable entity (e.g. current page), it might make sense to use a single key for this feature as a whole and to limit the stored information only to the last few iterations (LRU). The slight increase in retrieval cost (the whole key, instead of separate smaller ones) is considered worth it, as otherwise the number of keys would grow uncontrollably.

Even if the keys are not dependent on user-input, you may still want to use a single key for your feature because otherwise past versions of your software will have stored data that you can't clean up. By using a single key you can roundtrip it in a way that naturally doesn't persist unknown sub properties.

Use of a tracking key is also an anti-pattern and does not avoid the above issues, as this would leak due to race conditions in HTML5 web storage being shared and non-atomic between multiple open browser tabs.

When feature's use of Local storage is to be removed, be sure to implement an eviction strategy first to clean up old values. Typically mw.requestIdleCallback is used to gracefully look for the key and remove it. See T121646 for a more scalable approach.



Osobní údaje
Avoid storing personal information in Local storage as it remains when a user logs out or closes their browser. Use Session storage instead. See T179752.



Asynchronní kód
Asynchronous code should follow, and be compatible with, the Promise standard.

When you define an asynchronous method for other code to call, you may internally construct the returned thenable object either using $.Deferred or native Promise. Remember to depend on the  polyfill if using Promise (this polyfill is automatically skipped and excluded from your module bundle in modern browsers).

When you call an asynchronous method, use only standard Promise-compatible methods such as  and. Avoid using jQuery-specific methods like  or , which could stop working without warning if the method you are calling internally transitions from $.Deferred to native Promise.

Note that there are also subtle legacy behaviours in the "done" and "fail" callbacks. Pay close attention when migrating existing code from  to   as doing so may cause the code to stop working correctly. Specifically, the "done" and "fail" callbacks invoke your callback synchronously if the Deferred was already settled by the time you attach your callback. This means your callback may be invoked before the attaching statement is finished running.

For example:



Závěrečné poznámky


Opětovné použití modulů ResourceLoader
Don't reinvent the wheel. Much JavaScript functionality and MediaWiki-related utilities ship with MediaWiki core that are stable and you can (literally) depend on them. See ResourceLoader/Core modules before rolling your own code.

Úskalí
Read more:
 * Be careful to preserve compatibility with left-to-right and right-to-left languages (i.e.  or  ), especially when styling text containers. Putting those declarations in CSS file will allow them to be automatically flipped for RTL-languages by CSSJanus in ResourceLoader.
 * Use  and   appropriately.
 * jQuery#attr, jQuery API
 * Attributes and custom properties, javascript.info
 * Consistently quote attribute selector values:  instead of   (jqbug 8229).
 * As of jQuery 1.4 the jQuery constructor has a new feature that allows passing an object as second argument, like . Don't use this. It makes code harder to follow, fails on attributes (such as 'size') that are also methods, and is unstable due to this mixing of jQuery methods with element attributes. A future jQuery method or plugin called "title" might convert an element into a heading, which means the title attribute can also no longer be set through this method. Be explicit and call ,  ,   etc. directly.



Použijte CSS pro úpravu stylů mnoha prvků
Neaplikujte styl na mnoho prvků najednou. Oslabuje to výkon. Místo toho použijte společnou rodičovskou třídu (nebo jednu přidejte) a použijte CSS v souboru  nebo. Díky ResourceLoaderu se to vše načte ve stejném požadavku HTTP, takže za samostatný soubor CSS nedochází k žádnému snížení výkonu. Nenastavujte CSS do inline atributů "style", nevkládejte ani prvky "style" z JS.

Poznámky pod čarou

 * JavaScript Style Guide, Contribute to jQuery
 * Code Conventions for JavaScript, Douglas Crockford
 * Programming Style & Your Brain, Douglas Crockford on YouTube