Technologie WebAssembly a GopherJS: předávání argumentů mezi Go a JavaScriptem (dokončení)

23. 1. 2025
Doba čtení: 34 minut

Sdílet

Autor: Depositphotos
Ukážeme si předávání objektů, polí a funkcí z JavaScriptu do jazyka Go, pochopitelně včetně zpracování těchto datových typů. A jak je v této oblasti tradicí: nic není tak jednoduché, jak by mohlo být.

Obsah

1. Technologie WebAssembly a GopherJS: předávání argumentů mezi Go a JavaScriptem (dokončení)

2. Předání řetězce z JavaScriptu do Go

3. Otestování předání řetězce z JavaScriptu do Go

4. Předání objektu z JavaScriptu do Go

5. Demonstrační příklad: předání JavaScriptového objektu do funkce naprogramované v Go

6. Přístup k atributům JavaScriptového objektu z Go

7. Demonstrační příklad: přečtení vybraných atributů předaného JavaScriptového objektu

8. Konverze atributů předaného objektu do nativních typů Go

9. Demonstrační příklad: konverze všech atributů objektů do nativních typů jazyka Go

10. Předání pole, získání počtu prvků pole

11. Demonstrační příklad: předání pole do Go funkce se zjištěním jeho délky

12. Přístup k prvkům JavaScriptového pole z Go

13. Demonstrační příklad: výpis typů a hodnot všech prvků JavaScriptového pole

14. Součet prvků předaného pole

15. Demonstrační příklad: součet všech prvků pole předaného z JavaScriptu do Go

16. Předání funkce naprogramované v JavaScriptu do Go

17. Zavolání JavaScriptové funkce

18. Demonstrační příklad: zavolání JavaScriptové funkce z jazyka Go

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Technologie WebAssembly a GopherJS: předávání argumentů mezi Go a JavaScriptem (dokončení)

Připomeňme si, že v jazyce JavaScript můžeme pracovat s hodnotami různých typů. Ukázali jsme si i tabulku se základními datovými typy JavaScriptu:

(totéž platí i pro zápornou mezní hodnotu).
# Datový typ Stručný popis
1 Boolean datový typ se dvěma možnými hodnotami truefalse
2 String sekvence znaků (jediný znak je taktéž považován za řetězec)
3 Number reprezentuje hodnoty typu double podle IEEE 754; řada celých čísel je tedy omezena mezní hodnotou 253-1 (vlastně šířkou mantisy, i když skutečnost je nepatrně složitější, dtto pro zápornou mezní hodnotu)
4 Bigint speciální typ celočíselných numerických hodnot používaných v případě, že se ukládají hodnoty větší než 253-1
5 Null typ s jedinou hodnotou null
6 Undefined specialita JavaScriptu (a bolehlav), představuje ještě nepřiřazenou hodnotu (pozor: rozdílné od Null)
7 Symbol unikátní identifikátor
8 Object objekty (je to na první pohled zvláštní, ale sem spadají například i funkce)

Ve skutečnosti ovšem nesmíme zapomenout ještě na jeden datový typ, se kterým se později setkáme. Tímto datovým typem je funkce (function), která je v JavaScriptu (ostatně podobně jako i v některých dalších programovacích jazycích) považována za plnohodnotný datový typ.

Minule jsme si na několika příkladech ukázali, jakým způsobem lze do funkce naprogramované v jazyku Go předat argumenty typu Number. Ty bylo možné zkonvertovat na typ int a float64, s nimiž je možné v Go běžně pracovat (až na problém týkající se potenciálního menšího rozsahu typu int na 32bitových systémech). Naprosto stejným způsobem lze pracovat s pravdivostními hodnotami, které se zkonvertují na typ boolean.

U hodnot typu Null a Undefined se neprovádí skutečná konverze, ale pouze test, zda je zvolený argument typu Null či Undefined (samotný typ přímo určuje i hodnotu). Tyto testy se provádí metodami Value.IsNull() a Value.IsUndefined.

Zbývají nám tedy řetězce, objekty a v neposlední řadě taktéž funkce. A právě těmito typy a jejich konverzemi se budeme zabývat v dnešním článku.

Poznámka: zdánlivě chybí pole a mapy (slovníky). I ty jsou však předávány jakoby se jednalo o objekty.

2. Předání řetězce z JavaScriptu do Go

S řetězci se jak v JavaScriptu, tak i v jazyce Go pracuje obdobným způsobem, i když interně se může způsob ukládání řetězců lišit. V obou případech se však jedná o sekvenci Unicode znaků se známou délkou; navíc je tato sekvence v obou jazycích neměnitelná (immutable).

Pro převod JavaScriptového argumentu typu řetězec na plnohodnotný řetězec (z pohledu jazyka Go) se používá metoda Value.String(). Na rozdíl od ostatních metod pro konverzi hodnoty, s nimiž jsme se až doposud setkali (Value.Bool(), Value.Int() a Value.Float()) však metoda Value.String() „nezpanikaří“ ani v případě, kdy je předávaný argument odlišného typu. V takovém případě se provede konverze (libovolného) typu na řetězec „T:V“, kde za T se dosadí jméno typu a za V je dosazena hodnota v řetězcové podobě (a u typů Null a Undefined se uvádí pouze typ, protože ten přímo definuje i hodnotu).

3. Otestování předání řetězce z JavaScriptu do Go

V dnešním prvním demonstračním příkladu je ukázán způsob předání řetězce z JavaScriptu (tj. z libovolného kódu naprogramovaného v JavaScriptu) do funkce naprogramované v jazyku Go. V této funkci zkontrolujeme počet předaných argumentů (to již dobře známe, takže se již nebudu opakovat) a taktéž to, zda je typ prvního (a jediného) argumentu skutečně řetězcem:

// kontrola typu předaného argumentu
typ := args[0].Type()
if typ != js.TypeString {
        fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
        return nil
}

V případě, že je skutečně předán řetězec, provedeme konverzi z JavaScriptového řetězce na Go řetězec:

// provést konverzi
message := args[0].String()

Dále je již možné s proměnnou message pracovat stejně, jako s jakýmkoli jiným řetězcem v Go.

Úplný zdrojový kód takto vytvořeného demonstračního příkladu vypadá následovně:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů předaných funkci PrintMessage
// - kontrola typu argumentů předaných funkci PrintMessage
// - provedení konverze na nativní typy jazyka Go
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintMessage(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        // kontrola typu předaného argumentu
        typ := args[0].Type()
        if typ != js.TypeString {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // provést konverzi
        message := args[0].String()
 
        // zobrazit zprávu
        fmt.Println(message)
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce PrintMessage tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printMessage", js.FuncOf(PrintMessage))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

HTML stránka, ve které je funkce printMessage volána s různým typem i počty argumentů, vypadá takto:

<!doctype html>
<html>
    <head>
        <title>Function call: with string argument</title>
    </head>
    <body>
        <h1 id="header">Function call: with string argument</h2>
        <script src="func_call_string.js" type="text/javascript"></script>
        <script type="text/javascript">
            // korektní argumenty
            printMessage("");
            printMessage("Hello, world!");
            printMessage("příliš žluťoučký kůň");
 
            // špatný počet argumentů
            printMessage("foo", "bar")
            printMessage();
 
            // špatný typ argumentu
            printMessage(2);
            printMessage(null);
            printMessage(undefined);
        </script>
    </body>
</html>

A pochopitelně se podíváme i na výsledek volání funkce printMessage zobrazený v konzoli prohlížeče:

Obrázek 1: Výsledek volání funkce printMessage z JavaScriptu s různými typy a počty předávaných argumentů.

4. Předání objektu z JavaScriptu do Go

Objekty jsou v JavaScriptu používány pro mnoho účelů; navíc do této kategorie spadají například i pole, slovníky atd. Přímo v JavaScriptu lze objekty vytvářet (konstruovat) různými způsoby, například jako instance třídy, funkcionálním stylem atd. Ukažme si tu pravděpodobně nejjednodušší možnost konstrukce objektu, která vypadá následovně:

// konstrukce objektu
const person = new Object();
 
// přidání atributů
person.firstName = "John";
person.lastName = "Doe";
person.age = 42;
person.eyeColor = "blue";

Takový objekt lze předat do jazyka Go v argumentu volané funkce. V Go bude představován hodnotou typu js.Value. Bude možné zjistit, zda se skutečně jedná o hodnotu typu objekt a navíc lze i přistoupit k atributům tohoto objektu s využitím metody Value.Get (a jak uvidíme dále, existují i další podporované operace).

5. Demonstrační příklad: předání JavaScriptového objektu do funkce naprogramované v Go

Opět si prakticky ukažme, jakým způsobem je možné předat JavaScriptový objekt do funkce, která je naprogramovaná v jazyce Go. V této funkci opět nejprve zkontrolujeme počet předaných argumentů (postup již dobře známe) a následně pak typ předaného argumentu:

object := args[0]
 
// kontrola typu předaného argumentu
typ := object.Type()
if typ != js.TypeObject {
        fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
        return nil
}

V případě, že je předán korektní hodnota typu „objekt“, je textová reprezentace takového objektu vypsána na webovou konzoli.

Implementace části napsané v Go (včetně registrace funkce) může vypadat takto:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů předaných funkci PrintObject
// - kontrola typu argumentů předaných funkci PrintObject
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintObject(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        object := args[0]
 
        // kontrola typu předaného argumentu
        typ := object.Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // zobrazit objekt
        fmt.Println(object)
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce PrintObject tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printObject", js.FuncOf(PrintObject))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

Ve zdrojovém kódu webové stránky nejdříve vytvoříme nový objekt i s atributy. Tento objekt následně předáme do funkce naprogramované v Go:

<!doctype html>
<html>
    <head>
        <title>Function call: with object argument</title>
    </head>
    <body>
        <h1 id="header">Function call: with object argument</h2>
        <script src="func_call_object_1.js" type="text/javascript"></script>
        <script type="text/javascript">
            // konstrukce objektu
            const person = new Object();
 
            // přidání atributů
            person.firstName = "John";
            person.lastName = "Doe";
            person.age = 42;
            person.eyeColor = "blue";
 
            // zavolání funkce naprogramované v Go s předáním objektu
            printObject(person);
        </script>
    </body>
</html>

Výsledek zobrazený na webové konzoli by měl vypadat následovně:

Obrázek 2: Výsledek volání funkce printObject z JavaScriptu s předáním skutečného objektu.

6. Přístup k atributům JavaScriptového objektu z Go

Předpokládejme, že v prvním argumentu Go funkce volané z JavaScriptu je uložena hodnota typu Object. Pro zjednodušení programového kódu si tento objekt uložíme do pomocné proměnné nazvané taktéž object (v jazyce Go se nejedná o rezervované klíčové slovo):

object := args[0]

Nyní můžeme s využitím metody Value.Get() získat libovolný atribut objektu. Pokud atribut neexistuje, je vrácena hodnota typu undefined:

object.Get("firstName")
object.Get("lastName")
object.Get("age")
object.Get("eyeColor")
object.Get("somethingElse")
Poznámka: výsledkem je opět hodnota typu js.Value, nikoli nativní typ programovacího jazyka Go!

7. Demonstrační příklad: přečtení vybraných atributů předaného JavaScriptového objektu

V dnešním třetím demonstračním příkladu je ukázáno, jakým způsobem lze přečíst atributy (s předem známými jmény) z JavaScriptového objektu, který je předán do Go funkce. Go funkce nejdříve provede všechny testy, které jsme již viděli (počty a typy předaných argumentů) a následně pomocí metody Get() přečte hodnoty atributů:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů předaných funkci PrintObject
// - kontrola typu argumentu předaného funkci PrintObject
// - přečtení atributů z předaného objektu
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintObject(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        object := args[0]
 
        // kontrola typu předaného argumentu
        typ := object.Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // přečíst a zobrazit atributy objektu
        fmt.Printf("First name: %v\n", object.Get("firstName"))
        fmt.Printf("Last name:  %v\n", object.Get("lastName"))
        fmt.Printf("Age:        %v\n", object.Get("age"))
        fmt.Printf("Eye color:  %v\n", object.Get("eyeColor"))
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce PrintObject tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printObject", js.FuncOf(PrintObject))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

Příslušná HTML stránka, z níž je Go funkce zavolána a je jí předán objekt:

<!doctype html>
<html>
    <head>
        <title>Function call: with object argument</title>
    </head>
    <body>
        <h1 id="header">Function call: with object argument</h2>
        <script src="func_call_object_2.js" type="text/javascript"></script>
        <script type="text/javascript">
            // konstrukce objektu
            const person = new Object();
 
            // přidání atributů
            person.firstName = "John";
            person.lastName = "Doe";
            person.age = 42;
            person.eyeColor = "blue";
 
            // zavolání funkce naprogramované v Go s předáním objektu
            printObject(person);
        </script>
    </body>
</html>

A takto by měly vypadat výsledky vypsané do konzole webového prolížeče:

Obrázek 3: Výsledek volání funkce printObject z JavaScriptu s předáním skutečného objektu.

8. Konverze atributů předaného objektu do nativních typů Go

Opět nyní předpokládejme, že do Go funkce byl předán JavaScriptový objekt v prvním argumentu. Můžeme si ho tedy uložit do pomocné proměnné:

object := args[0]

Atribut firstName by měl obsahovat řetězec, takže můžeme přímo provést jeho konverzi z js.Value na typ string. V tomto případě můžeme nejdříve provést i test, zda je atribut správného typu, popř. lze tento test vynechat a přímo psát:

firstName := object.Get("firstName").String()

Podobně je možné získat obsah atributu age ve formě celého čísla:

age := object.Get("age").Int()
Poznámka: v tomto případě již může konverzní funkce „zpanikařit“, takže by bylo vhodnější nejdříve typ atributu explicitně otestovat:
typ := object.Get("age").Type()
if typ != js.TypeInt {
        ...
        ...
        ...
}

9. Demonstrační příklad: konverze všech atributů objektů do nativních typů jazyka Go

Ukažme si nyní, jakým způsobem se načtou všechny (předem známé) atributy objektu předaného do Go s následnou konverzí těchto atributů na nativní datové typy Go:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů funkci PrintObject
// - kontrola typu argumentů předaných funkci PrintObject
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintObject(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        object := args[0]
 
        // kontrola typu předaného argumentu
        typ := object.Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // převést atributy do nativních typů jazyka Go
        firstName := object.Get("firstName").String()
        lastName := object.Get("lastName").String()
        age := object.Get("age").Int()
        eyeColor := object.Get("eyeColor").String()
 
        // zobrazit atributy objektu
        fmt.Printf("First name: %s (%T)\n", firstName, firstName)
        fmt.Printf("Last name:  %s (%T)\n", lastName, lastName)
        fmt.Printf("Age:        %d (%T)\n", age, age)
        fmt.Printf("Eye color:  %s (%T)\n", eyeColor, eyeColor)
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce PrintObject tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printObject", js.FuncOf(PrintObject))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

HTML stránka, ze které se volá zaregistrovaná Go funkce, vypadá takto:

<!doctype html>
<html>
    <head>
        <title>Function call: with object argument</title>
    </head>
    <body>
        <h1 id="header">Function call: with object argument</h2>
        <script src="func_call_object_3.js" type="text/javascript"></script>
        <script type="text/javascript">
            // konstrukce objektu
            const person = new Object();
 
            // přidání atributů
            person.firstName = "John";
            person.lastName = "Doe";
            person.age = 42;
            person.eyeColor = "blue";
 
            // zavolání funkce naprogramované v Go s předáním objektu
            printObject(person);
        </script>
    </body>
</html>

Po načtení výše uvedené HTML stránky do webového prohlížeče by se v jeho konzoli měly zobrazit tyto řádky s atributy předaného objektu:

Obrázek 4: Výpis typů a hodnot atributů předaných do Go funkce z JavaScriptového kódu.

10. Předání pole, získání počtu prvků pole

V JavaScriptu lze vytvářet i pole, která se chovají jako měnitelné heterogenní kontejnery. Pole jsou měnitelná z toho důvodu, že prvky v poli je možné modifikovat a navíc lze do pole přidávat další prvky, popř. prvky odebírat (například metodami push, pop, shift a když víte, co děláte, tak i metodou delete). Pole jsou heterogenní proto, že každý prvek pole může být jakéhokoli typu. Nejjednodušší způsob konstrukce pole spočívá v použití literálu, který v případě polí znamená zápis hodnot prvků mezi hranaté závorky:

[]
[1]
[1, 2, 3]
["foo", "bar", "baz"]
[true, false]

V případě heterogenního pole pak i:

[42, "is", true, "answer"]

Z pohledu typového systému programovacího jazyka JavaScript jsou pole objekty, které mají definovaných cca patnáct standardních metod a taktéž atribut length vracející délku pole. To znamená, že i v příslušné Go funkci budeme s takovým polem muset pracovat jako s objektem.

Jen pro úplnost si atribut i standardní metody pole vypišme:

Atribut/metoda
Array length
Array toString()
Array at()
Array join()
Array pop()
Array push()
Array shift()
Array unshift()
Array delete()
Array concat()
Array copyWithin()
Array flat()
Array splice()
Array toSpliced()
Array slice()

11. Demonstrační příklad: předání pole do Go funkce se zjištěním jeho délky

Pro datovou strukturu js.Value je definována i metoda nazvaná Length, která v případě polí vrací jejich délku a v případě objektů jiných typů hodnotu vlastnosti length (samozřejmě v případě, pokud tato vlastnost existuje, mimochodem existuje i u řetězců). To znamená, že délku pole je možné v jazyce Go zjistit následujícím způsobem:

// získat atribut s délkou pole
array := args[0]
length := array.Length()

V demonstračním příkladu se zjistí délka pole, která se následně vypíše do webové konzole:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů funkci PrintArrayLength
// - kontrola typu argumentů předaných funkci ArrayLength
// - výpočet délky pole předaného do Go funkce
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintArrayLength(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        // kontrola typu typu předaného argumentu
        typ := args[0].Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // získat atribut s délkou pole
        array := args[0]
        length := array.Length()
 
        // zobrazit zprávu
        fmt.Printf("Array length = %d\n", length)
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce printArrayLength tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printArrayLength", js.FuncOf(PrintArrayLength))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

HTML stránka pro otestování chování:

<!doctype html>
<html>
    <head>
        <title>Function call: array as argument</title>
    </head>
    <body>
        <h1 id="header">Function call: array as argument</h2>
        <script src="func_call_array_1.js" type="text/javascript"></script>
        <script type="text/javascript">
            // korektní argumenty
            printArrayLength([]);
            printArrayLength([1]);
            printArrayLength([1, 2, 3]);
            printArrayLength(["foo", "bar", "baz"])
            printArrayLength([true, false]);
        </script>
    </body>
</html>

Obrázek 5: Výpis délek polí jištěných ve funkci naprogramované v jazyce Go.

Pozor ovšem na „děravé“ pole, které bude vracet počet prvků včetně „děr“ (tedy prvků s nespecifikovanou hodnotou):

arr = [1, 2, 3, 4];
delete arr[2];
printArrayLength(arr);

V tomto případě se zjistí a vypíše hodnota 4.

12. Přístup k prvkům JavaScriptového pole z Go

V případě, že je nutné v jazyce Go pracovat s prvky (obsahem) polí předaných z JavaScriptu, je nutné tyto prvky konvertovat postupně. To znamená, že nemáme k dispozici žádnou univerzální konverzní funkci (nebo sadu funkcí), která by například dokázala vrátit Go pole s prvky typu int nebo string. Takové konverzní funkce neexistují z toho důvodu, že pole mohou být v JavaScriptu heterogenní.

Přístup k prvkům polí tedy musí být proveden postupně, k čemuž použijeme metodu Index, která pro zadaný index (celé číslo) vrátí n-tý prvek pole typu js.Value. S tímto prvkem následně pracujeme jako s jakoukoli jinou JavaScriptovou hodnotou: můžeme zjistit jeho typ, provést konverzi atd.

Nejprve (po příslušných kontrolách, které již známe) získáme hodnotu argumentu předaného do Go funkce:

array := args[0]

Jedná se přitom o pole, takže přečteme jeho délku metodou Value.Length():

length := array.Length()
 
// zobrazit zprávu
fmt.Printf("Array length = %d\n", length)

Následně explicitně projdeme všemi prvky pole a zjistíme typ a hodnotu těchto prvků (a to včetně případných „děr“, které pole mohou obsahovat):

// projít prvky pole
for i := 0; i < length; i++ {
        item := array.Index(i)
        fmt.Printf("Item #%d has type = %s and value %v\n",
                i,
                item.Type(),
                item)
}

13. Demonstrační příklad: výpis typů a hodnot všech prvků JavaScriptového pole

V dalším demonstračním příkladu je ukázán průchod všemi prvky pole předaného z JavaScriptu do Go, přičemž pro každý prvek je vypsán jeho typ i hodnota:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů předaných funkci PrintArray
// - kontrola typu argumentů předaných funkci PrintArray
// - výpočet délky pole
// - výpis prvků pole
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func PrintArray(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        // kontrola typu předaného argumentu
        typ := args[0].Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // získat atribut s délkou pole
        array := args[0]
        length := array.Length()
 
        // zobrazit zprávu
        fmt.Printf("Array length = %d\n", length)
 
        // projít prvky pole
        for i := 0; i < length; i++ {
                item := array.Index(i)
                fmt.Printf("Item #%d has type = %s and value %v\n",
                        i,
                        item.Type(),
                        item)
        }
 
        fmt.Println()
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce printArray tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("printArray", js.FuncOf(PrintArray))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

HTML stránka, ze které výše deklarovanou funkci printArray (resp. přesněji řečeno PrintArray) voláme, vypadá takto:

<!doctype html>
<html>
    <head>
        <title>Function call: array as argument</title>
    </head>
    <body>
        <h1 id="header">Function call: array as argument</h2>
        <script src="func_call_array_2.js" type="text/javascript"></script>
        <script type="text/javascript">
            // korektní argumenty
            printArray([]);
            printArray([1]);
            printArray([1, 2, 3]);
            printArray(["foo", "bar", "baz"])
            printArray([true, false]);
        </script>
    </body>
</html>

Podívejme se na výsledky vypsané do konzole webového prohlížeče:

Obrázek 6: Výpis prvků polí z jazyka Go.

Pro „děravé pole“, v níž chybí prvek s indexem 2, se vypíše:

Array length = 4 func_call_array_2.js:45:25
Item #0 has type = number and value <number: 1> func_call_array_2.js:45:25
Item #1 has type = number and value <number: 2> func_call_array_2.js:45:25
Item #2 has type = undefined and value <undefined> func_call_array_2.js:45:25
Item #3 has type = number and value <number: 4> func_call_array_2.js:45:25

14. Součet prvků předaného pole

Předpokládejme, že JavaScriptové pole předávané do funkce naprogramované v jazyku Go obsahuje pouze číselné hodnoty (a je jedno, zda celá čísla nebo čísla s plovoucí řádovou čárkou). Například:

arr = [1, 1.5, 2, 100, -10]

V případě, že budeme chtít sečíst všechny prvky tohoto pole, lze postupovat následujícím způsobem. Nejdříve získáme argument s polem a zjistíme počet prvků pole (ještě předtím je ovšem vhodné zkontrolovat typ argumentu):

// získat atribut s délkou pole
array := args[0]
length := array.Length()

Následně můžeme využít sekvenci operací array.Index(i), která získá jeden z prvků pole (typu js.Value), za níž následuje operace Value.Int(), jež hodnotu převede na nativní celočíselnou hodnotu jazyka Go (pozor na 32bitové platformy!). Mezitím je více než vhodné zkontrolovat typ prvku, protože již víme, že JavaScriptová pole mohou být heterogenní. Výpočet sumy je pak snadný:

for i := 0; i < length; i++ {
        item := array.Index(i)
        typ := item.Type()
        if typ != js.TypeNumber {
                fmt.Printf("Item #%d has incorrect type %s\n", i, typ.String())
                return nil
        }
        value := item.Int()
        sum += value
}

15. Demonstrační příklad: součet všech prvků pole předaného z JavaScriptu do Go

Výše uvedený postup pro výpočet součtu všech prvků pole je prakticky ukázán na následujícím demonstračním příkladu. Je část naprogramovaná v jazyce Go vypadá následovně:

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - kontrola počtu argumentů předaných funkci arraySum
// - kontrola typu argumentů předaných funkci arraySum
// - výpočet délky pole
// - výpočet součtu prvků pole
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
// funkce, která se bude volat z HTML stránky, jakoby
// se jednalo o JavaScriptovou funkci
func ArraySum(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        // kontrola typu předaného argumentu
        typ := args[0].Type()
        if typ != js.TypeObject {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        // získat atribut s délkou pole
        array := args[0]
        length := array.Length()
 
        // zobrazit zprávu
        fmt.Printf("Array length = %d\n", length)
 
        // projít prvky pole a vypočítat sumu
        sum := 0
 
        for i := 0; i < length; i++ {
                item := array.Index(i)
                typ := item.Type()
                if typ != js.TypeNumber {
                        fmt.Printf("Item #%d has incorrect type %s\n", i, typ.String())
                        return nil
                }
                value := item.Int()
                sum += value
        }
        fmt.Printf("Sum = %d\n", sum)
        fmt.Println()
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        // export funkce arraySum tak, aby byla volatelná
        // z JavaScriptu
        js.Global().Set("arraySum", js.FuncOf(ArraySum))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

V JavaScriptu se pokusíme funkci arraySum zavolat s prázdným polem, s polem obsahujícím celočíselné hodnoty, ale taktéž s polem, které obsahuje hodnoty jiného typu:

<!doctype html>
<html>
    <head>
        <title>Function call: array sum</title>
    </head>
    <body>
        <h1 id="header">Function call: array sum</h2>
        <script src="func_call_array_sum.js" type="text/javascript"></script>
        <script type="text/javascript">
            // korektní argumenty
            arraySum([]);
            arraySum([1]);
            arraySum([1, 2, 3]);
            arraySum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
 
            // nekorektní argumenty
            arraySum(["foo", "bar", "baz"])
            arraySum([true, false]);
        </script>
    </body>
</html>

Výsledek by měl po spuštění ve webovém prohlížeči vypadat následovně:

Obrázek 7: Součty prvků polí s celočíselnými prvky, popř. chyby u polí, které obsahují prvky odlišného typu.

16. Předání funkce naprogramované v JavaScriptu do Go

V úvodní kapitole jsme si řekli, že funkce jsou v JavaScriptu (ale i v jazyce Go) plnohodnotným datovým typem, takže je možné funkci předat jako argument do jiné funkce, popř. naopak získat funkci jako návratovou hodnotu z jiné volané funkce. V takovém případě mluvíme o funkcích vyššího řádu, to je však téma přesahující tento článek. Ukážeme si namísto toho, jakým způsobem lze do jazyka Go předat JavaScriptovou funkci (resp. referenci na ni) a jak tuto funkci z Go zavolat.

Ze strany JavaScriptu může celý problém vypadat následovně – nadeklarujeme funkci nazvanou foo a tu předáme do funkce nazvané callFunction. Přitom nevíme a ani nás nemusí zajímat, zda se jedná o JavaScriptovou funkci nebo o funkci naprogramovanou v Go a transpilovanou do JavaScriptu nebo spuštěnou v rámci WebAssembly:

<script type="text/javascript">
function foo(message) {
    window.alert(message);
}
 
callFunction(foo);
</script>

17. Zavolání JavaScriptové funkce

Na straně Go tedy máme argument, který by měl být typu js.TypeFunction. To si můžeme velmi snadno ověřit:

// kontrola typu předaného argumentu
typ := args[0].Type()
if typ != js.TypeFunction {
        ...
        ...
        ...
}

Pokud je argument skutečně typu „javascriptová funkce“, můžeme tuto funkci zavolat a předat jí libovolné argumenty. Pro tento účel se používá metoda Invoke s hlavičkou:

func (v Value) Invoke(args ...any) Value
Poznámka: povšimněte si, že můžeme předat libovolný počet (a typ) argumentů, které jsou automaticky převedeny z Go do JavaScriptové obdoby. Výsledkem je opět hodnota typu js.Value, se kterou můžeme dále pracovat.

Příklad zavolání funkce, jejíž referenci jsme získali, a předání řetězce do této funkce:

function := args[0]
 
function.Invoke("Called from Go!")

18. Demonstrační příklad: zavolání JavaScriptové funkce z jazyka Go

V dnešním posledním demonstračním příkladu je ukázán postup popsaný v předchozích dvou kapitolách. V Go části aplikace otestujeme, zda je předán argument typu „javascriptová funkce“ a pokud tomu tak je, tuto funkci zavoláme a předáme jí řetězec (ten je automaticky zkonvertován):

// Technologie WebAssembly a GopherJS
//
// - rozhraní mezi jazyky Go a JavaScript
// - zavolání callback funkce
 
package main
 
import (
        "fmt"
        "syscall/js"
)
 
func CallFunction(this js.Value, args []js.Value) any {
        // kontrola počtu předaných argumentů
        if len(args) != 1 {
                fmt.Printf("incorrect number of arguments %d, but exactly one is accepted\n", len(args))
                return nil
        }
 
        // kontrola typu předaného argumentu
        typ := args[0].Type()
        if typ != js.TypeFunction {
                fmt.Printf("Argument #0 has incorrect type %s\n", typ.String())
                return nil
        }
 
        function := args[0]
 
        function.Invoke("Called from Go!")
 
        // je nutné vrátit nějakou hodnotu
        return nil
}
 
func main() {
        fmt.Println("started")
 
        c := make(chan bool)
 
        js.Global().Set("callFunction", js.FuncOf(CallFunction))
 
        // realizace nekonečného čekání
        // (nutno provést při překladu do WebAssembly, ktežto
        // v případě použití GopherJS je možné hlavní funkci ukončit)
        <-c
 
        fmt.Println("finished")
}

Na HTML stránce je nejdříve nadeklarována nová JavaScriptová funkce. Ta je následně předána do kódu naprogramovaného v Go:

<!doctype html>
<html>
    <head>
        <title>Callback</title>
    </head>
    <body>
        <h1 id="header">Callback</h2>
        <script src="callback.js" type="text/javascript"></script>
        <script type="text/javascript">
        function foo(message) {
            window.alert(message);
        }
 
        callFunction(foo);
        </script>
    </body>
</html>

Po zobrazení HTML stránky se nejprve vytvoří funkce foo, následně je předána do Go a poté je odsud spuštěna. Výsledkem by měl být dialog zobrazený voláním window.alert, přičemž zprávou je řetězec předaný v Go:

Obrázek 8: Dialog vyvolaný nepřímo z jazyka Go.

hacking_tip

19. Repositář s demonstračními příklady

Demonstrační příklady napsané v jazyce Go, které jsou určené pro transpřeklad do JavaScriptu s využitím nástroje GopherJS, byly uloženy do Git repositáře, jenž je dostupný na adrese https://github.com/RedHatOf­ficial/GoCourse. Jednotlivé demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:

# Příklad Stručný popis Adresa
1 func_call_no_arguments.go první demonstrační příklad: zavolání Go funkce bez předání argumentů https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_no_argumen­ts.go
2 func_call_no_arguments.html HTML stránka s kódem pro načtení prvního demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_no_argumen­ts.html
       
3 func_call_with_arguments.go druhý demonstrační příklad: výpis všech argumentů předaných funkci volané z JavaScriptu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_with_argu­ments.go
4 func_call_with_arguments.html HTML stránka s kódem pro načtení druhého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_with_argu­ments.html
       
5 func_call_argument_types1.go třetí demonstrační příklad: výpis typu argumentů, které jsou obaleny strukturou js.Value https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_argument_ty­pes1.go
6 func_call_argument_types1.html HTML stránka s kódem pro načtení třetího demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_argument_ty­pes1.html
       
7 func_call_argument_types2.go čtvrtý demonstrační příklad: vylepšené řešení tisku argumentů funkce volané z JavaScriptu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_argument_ty­pes2.go
8 func_call_argument_types2.html HTML stránka s kódem pro načtení čtvrtého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_argument_ty­pes2.html
       
9 func_call_two_ints.go pátý demonstrační příklad: realizace předání a konverze dvou argumentů typu celé číslo https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_two_ints.go
10 func_call_two_ints.html HTML stránka s kódem pro načtení pátého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_two_ints.html
       
11 func_call_two_floats.go šestý demonstrační příklad: realizace předání a konverze dvou argumentů typu double https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_two_float­s.go
12 func_call_two_floats.html HTML stránka s kódem pro načtení šestého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_two_float­s.html
       
13 func_call_return_int1.go sedmý demonstrační příklad: vrácení hodnoty typu int do JavaScriptu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_return_in­t1.go
14 func_call_return_int1.html HTML stránka s kódem pro načtení sedmého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_return_in­t1.html
       
15 func_call_return_int2.go osmý demonstrační příklad: vrácení hodnoty typu int do JavaScriptu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_return_in­t2.go
16 func_call_return_int2.html HTML stránka s kódem pro načtení osmého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_return_in­t2.html
       
17 func_call_string.go devátý demonstrační příklad: předání řetězce z JavaScriptu do Go https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_string.go
18 func_call_string.html HTML stránka s kódem pro načtení devátého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_string.html
       
19 func_call_object1.go desátý demonstrační příklad: předání objektu z JavaScriptu do Go https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object1.go
20 func_call_object1.html HTML stránka s kódem pro načtení desátého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object1.html
       
21 func_call_object2.go jedenáctý demonstrační příklad: přístup k atributům předaného objektu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object2.go
22 func_call_object2.html HTML stránka s kódem pro načtení jedenáctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object2.html
       
23 func_call_object3.go dvanáctý demonstrační příklad: konverze atributů předaného objektu do nativních typů Go https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object3.go
24 func_call_object3.html HTML stránka s kódem pro načtení dvanáctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_object3.html
       
25 func_call_array1.go třináctý demonstrační příklad: předání pole se získáním počtu prvků https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array1.go
26 func_call_array1.html HTML stránka s kódem pro načtení třináctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array1.html
       
27 func_call_array2.go čtrnáctý demonstrační příklad: výpis prvků předaného pole https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array2.go
28 func_call_array2.html HTML stránka s kódem pro načtení čtrnáctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array2.html
       
29 func_call_array_sum.go patnáctý demonstrační příklad: součet prvků předaného pole https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array_sum­.go
30 func_call_array_sum.html HTML stránka s kódem pro načtení patnáctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/func_call_array_sum­.html
       
31 callback.go šestnáctý demonstrační příklad: předání funkce s jejím zavoláním https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/callback.go
32 callback.html HTML stránka s kódem pro načtení šestnáctého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/callback.html

Pro úplnost si uveďme i odkazy na ukázkové příklady použité minule:

# Příklad Stručný popis Adresa
1 hello_world.go zdrojový kód prvního demonstračního příkladu: výpis zprávy na konzoli webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/hello_world.go
1 hello_world.html HTML stránka s kódem pro načtení prvního demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/hello_world.html
       
2 dom_manipulation.go zdrojový kód druhého demonstračního příkladu: manipulace s DOMem webové stránky https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/dom_manipulation.go
2 dom_manipulation.html HTML stránka s kódem pro načtení druhého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/dom_manipulation.html
       
3 dom_add_element.go zdrojový kód třetího demonstračního příkladu: přidání elementů do DOMu webové stránky https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/dom_add_element.go
3 dom_add_element.html HTML stránka s kódem pro načtení třetího demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/dom_add_element.html
       
4 draw_into_canvas.go zdrojový kód čtvrtého demonstračního příkladu: kreslení do canvasu https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/draw_into_canvas.go
4 draw_into_canvas.html HTML stránka s kódem pro načtení čtvrtého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/draw_into_canvas.html
       
5 js_interop1.go zdrojový kód pátého demonstračního příkladu: komunikace s JavaScriptem https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/js_interop1.go
5 js_interop1.html HTML stránka s kódem pro načtení pátého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/js_interop1.html
       
6 js_interop2.go zdrojový kód šestého demonstračního příkladu: komunikace s JavaScriptem https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/js_interop2.go
6 js_interop2.html HTML stránka s kódem pro načtení šestého demonstračního příkladu do webového prohlížeče https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/js_interop2.html
       
7 http_server.go implementace HTTP serveru, který dokáže webovému prohlížeči předávat obsah požadovaných souborů https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/http_server.go
       
8 hello_world2.go varianta programu typu „Hello, world!“, která volá pouze funkci println() https://github.com/RedHatOf­ficial/GoCourse/blob/master/les­son12/hello_world2.go

20. Odkazy na Internetu

  1. go2js
    https://github.com/tredoe/go2js
  2. GitHub repositář projektu GopherJS
    https://github.com/gopherjs/gopherjs
  3. How to use GopherJS to turn Go code into a JavaScript library
    https://medium.com/@kentquirk/how-to-use-gopherjs-to-turn-go-code-into-a-javascript-library-1e947703db7a
  4. Source to source compiler
    https://en.wikipedia.org/wiki/Source-to-source_compiler
  5. Binary recompiler
    https://en.wikipedia.org/wi­ki/Binary_recompiler
  6. py2many na GitHubu
    https://github.com/py2many/py2many
  7. py2many na PyPi
    https://pypi.org/project/py2many/
  8. Awesome Transpilers
    https://github.com/milahu/awesome-transpilers
  9. WebAssembly
    https://webassembly.org/
  10. WebAssembly na Wiki Golangu
    https://github.com/golang/go/wi­ki/WebAssembly
  11. The future of WebAssembly – A look at upcoming features and proposals
    https://blog.scottlogic.com/2018/07/20/wasm-future.html
  12. Writing WebAssembly By Hand
    https://blog.scottlogic.com/2018/04/26/we­bassembly-by-hand.html
  13. WebAssembly Specification
    https://webassembly.github­.io/spec/core/index.html
  14. Index of Instructions
    https://webassembly.github­.io/spec/core/appendix/in­dex-instructions.html
  15. The WebAssembly Binary Toolkit
    https://github.com/WebAssembly/wabt
  16. Will WebAssembly replace JavaScript? Or Will WASM Make JavaScript More Valuable in Future?
    https://dev.to/vaibhavshah/will-webassembly-replace-javascript-or-will-wasm-make-javascript-more-valuable-in-future-5c6e
  17. Roadmap (pro WebAssemly)
    https://webassembly.org/roadmap/
  18. Transcrypt
    https://transcrypt.org/
  19. JavaScript Data Types
    https://www.geeksforgeeks­.org/javascript-data-types/
  20. Standardní balíček syscall/js
    https://pkg.go.dev/syscall/js
  21. Data types
    https://javascript.info/types
  22. Datové typy (napsáno poněkud zjednodušeně)
    https://naucme.it/chapter/qa-04
  23. Primitive (JavaScript)
    https://developer.mozilla.org/en-US/docs/Glossary/Primitive
  24. JavaScript type: String
    https://developer.mozilla.org/en-US/docs/Glossary/String
  25. JavaScript type: Number
    https://developer.mozilla.org/en-US/docs/Glossary/Number
  26. JavaScript type: Boolean
    https://developer.mozilla.org/en-US/docs/Glossary/Boolean
  27. JavaScript type: Undefined
    https://developer.mozilla.org/en-US/docs/Glossary/Undefined
  28. JavaScript type: Null
    https://developer.mozilla.org/en-US/docs/Glossary/Null
  29. JavaScript type: Symbol
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Re­ference/Global_Objects/Sym­bol
  30. JavaScript type: BigInt
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Re­ference/Global_Objects/Bi­gInt

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.