JavaScript und die Webprogrammierung
michael.eichberg@dhbw-mannheim.de, Raum 149B
1.0
Seit 2016 gibt es jährliche Updates (ECMAScript 2016, 2017, 2018, 2019, 2020, 2021, 2022, ...)
Objektorientiert
Protoypische Vererbung
Objekte erben von anderen Objekten.
Objekte als allgemeine Container
(Im Grunde eine Vereinheitlichung von Objekten und Hashtabellen.)
seit ES6 werden auch Klassen unterstützt; diese sind aber nur syntaktischer Zucker.
Skriptsprache
Loose Typing/Dynamische Typisierung
Load and go-delivery (Lieferung als Text/Quellcode)
Garbage Collected
Single-Threaded
Funktionen sind Objekte erster Klasse
Ein (globaler) Namespace
Syntaktisch eine Sprache der "C"-Familie (viele Ähnlichkeiten zu Java)
Standardisiert durch die ECMA (ECMAScript)
Verwendet ganz insbesondere in Browsern, aber auch Serverseitig (Node.js) oder in Desktop-Anwendungen (Electron)
1let i = 1; // double-precision 64-bit binary IEEE 754 value
2let f = 1.0; // double-precision 64-bit binary IEEE 754 value
3console.log(
4Number.MIN_VALUE,
5Number.MIN_SAFE_INTEGER,
6Number.MAX_SAFE_INTEGER,
7Number.MAX_VALUE);
8let ib = 1n; // Number.MAX_SAFE_INTEGER 9007199254740991n
9console.log(100n === BigInt(100));
10let x = NaN;
11let y = Infinity;
12let z = -Infinity;
1314
let b = true; // oder false
15console.log("Boolean(undefined)", Boolean(undefined));
1617
// we have the standard operators: +, - , *, /, %, ++, --, **
18// and the bitwise operators: &, |, ^, ~, <<, >>, >>>
19console.log("i++ ", i++); // 1 oder 2?
20console.log("++i ", ++i); // 2 oder 3?
21console.log("2 ** 4 ", 2 ** 4);
22console.log("7 % 3 ", 7 % 3);
2324
25
let _s = "42";
26console.log('Die Antwort ist ' + _s); // Template literals (Template strings)
27console.log(`Die Antwort ist ${_s}.`); // Template literals (Template strings)
28console.log(`
29Die Antwort mag ${_s} sein,
30aber was ist die Frage?`);
3132
console.log(String(42)); // "42"
3334
35
let anonymousObj = {
36i: 1,
37u: { j: 2, v: { k: 3 } },
38toString: function () { return "anonymousObj"; }
39};
4041
// Zugriff auf die Eigenschaften eines Objekts
42anonymousObj.j = 2; // mittels Bezeichner ("j") (eng. Identifier)
43anonymousObj["j"] = 4; // mittels String ("j")
44anonymousObj["k"] = 3;
45console.log("anonymousObj", anonymousObj);
46console.log("anonymousObj.toString()", anonymousObj.toString());
47delete anonymousObj.toString;
48console.log("anonymousObj.toString() [original]", anonymousObj.toString());
49console.log("anonymousObj.u?.v.k", anonymousObj.u?.v.k); // Chain-Operator
50console.log("anonymousObj.u.v?.k", anonymousObj.u.v?.k);
51console.log("anonymousObj.u.q?.k", anonymousObj.u.q?.k);
52console.log("anonymousObj.p?.v.k", anonymousObj.p?.v.k);
5354
let date = new Date("8.6.2024") // ACHTUNG: Locale-Settings
55console.log(date);
5657
let $a = [1];
5859
let emptyObject = null;
6061
let func = function () { return "Hello World"; };
62console.log(func, func());
6364
let sym1 = Symbol("1"); // a unique and immutable primitive value
65let sym2 = Symbol("1");
66let obj1Values = { sym1: "value1", sym2: "value2" };
67console.log(obj1Values);
68console.log("sym1 in obj1Values: ", sym1 in obj1Values);
69let obj2Values = { [sym1]: "value1", [sym2]: "value2" };
70console.log("sym1 in obj2Values: ", sym1 in obj2Values);
71console.log(obj1Values, " vs. ", obj2Values);
7273
let u = undefined;
7475
76
// We have the standard logical operators: &&, ||, ! and also ??
7778
/* Operator Madness */
79console.log("1 && \"1\": ", 1 && '1');
80console.log("null && \"1\": ", null && '1');
81console.log("null && true: ", null && true);
82console.log("true && null: ", true && null);
83console.log("null && false: ", null && false);
84console.log("{} && true: ", {} && true);
8586
// nullish coalescing operator (??) (vergleichbar zu ||)
87console.log("1 ?? \"1\": ", 1 ?? '1');
88console.log("null ?? \"1\": ", null ?? '1');
89console.log("null ?? true: ", null ?? true);
90console.log("true ?? null: ", true ?? null);
91console.log("null ?? false: ", null ?? false);
92console.log("{} ?? true: ", {} ?? true);
9394
// Nützliche Zuweisungen
9596
anonymousObj.name ||= "Max Mustermann"
1/* requires node.js */
2"use strict";
3const Queue = require("./Queue");
45
const messages = new Queue();
67
function log(message, ...args) {
8messages.enqueue([message]);
9messages.enqueue(args);
10}
1112
// Gleichheit == // mit Typumwandlung (auch bei <, >, <=, >=)
13// Ungleichheit !==
14// strikt gleich === // ohne Typumwandlung
15// strikt ungleich !===
1617
log('1 == "1": ', 1 == "1");
18log('1 === "1": ', 1 === "1");
19log("1.0 == 1: ", 1 == 1.0);
20log("1 === 1n: ", 1 === 1n);
2122
log("asdf" === "as" + "df");
2324
log("null == NaN: ", null == NaN);
25log("null == NaN: ", null == NaN);
26log("null == null: ", null == null);
27log("null === null: ", null === null);
28log("undefined == undefined: ", undefined == undefined);
29log("undefined === undefined: ", undefined == undefined);
30log("null == undefined: ", null == undefined);
31log("null === undefined: ", null == undefined);
3233
const a1 = [1, 2, 3];
34const a2 = [1, 2, 3];
35log("a1 == [1,2,3]: ", a1 == [1, 2, 3]);
36log("a1 == a1: ", a1 == a1);
37log("a1 === a1: ", a1 === a1);
38log("a1 === a2: ", a1 === a2);
39log("a1 == a2: ", a1 == a2);
40log(
41"flatEquals(a1,a2):",
42a1.length == a2.length && a1.every((v, i) => v === a2[i]),
43);
4445
let firstJohn = { person: "John" };
46let secondJohn = { person: "John" };
47let basedOnFirstJohn = Object.create(firstJohn);
48log("firstJohn == firstJohn: ", firstJohn == firstJohn);
49log("firstJohn === secondJohn: ", firstJohn === secondJohn);
50log("firstJohn == secondJohn: ", firstJohn == secondJohn);
51log("firstJohn == basedOnFirstJohn: ", firstJohn == basedOnFirstJohn);
52log("firstJohn === basedOnFirstJohn: ", firstJohn === basedOnFirstJohn);
5354
let sym1 = Symbol("1"); // a unique and immutable primitive value
55log(sym1, sym1, "===", sym1 === sym1); // true
56let sym2 = Symbol("1");
57let objValues = { sym1: "value1", sym2: "value2" };
58log(objValues);
59let obj2Values = { [sym1]: "value1", [sym2]: "value2" };
60log(objValues, " === ", obj2Values, " vs. ", objValues === obj2Values);
61let obj1Value = { [sym1]: "value1", [sym1]: "value2" };
62log(obj2Values, " vs. ", obj1Value);
63log(sym1, sym2, "===", sym1 === sym2); // false
64log(sym1, sym2, "==", sym1 == sym2); // false
65log(Symbol.for("1"), sym1, "==", Symbol.for("1") === sym1);
6667
{
68const obj = {
69name: "John",
70age: 30,
71city: "Berlin",
72};
73log("\nTyptests und Feststellung des Typs:");
74log("typeof obj", typeof obj);
75log("obj instanceof Object", obj instanceof Object);
76log("obj instanceof Array", obj instanceof Array);
77}
78{
79const obj = { a: "lkj" };
80const obj2 = Object.create(obj);
81log(obj2 instanceof obj.constructor);
82}
8384
log("\n?-Operator and Truthy and Falsy Values:");
85log('""', "" ? "is truthy" : "is falsy");
86log("f()", (() => {}) ? "is truthy" : "is falsy");
87log("Array ", Array ? "is truthy" : "is falsy");
88log("obj ", obj ? "is truthy" : "is falsy");
89log("undefined ", undefined ? "is truthy" : "is falsy");
90log("null ", null ? "is truthy" : "is falsy");
91log("0", 0 ? "is truthy" : "is falsy");
92log("1", 1 ? "is truthy" : "is falsy");
9394
process.stdin.on("data", () => {
95const args = messages.dequeue();
96for (const arg of args) {
97process.stdout.write(String(arg));
98process.stdout.write(" ");
99}
100if (messages.isEmpty()) {
101process.exit();
102}
103});
1'use strict';
23
const arr = [1, 3, 4, 7, 11, 18, 29];
45
console.log("\If-elseif-else:");
6if (arr.length == 7) {
7console.log("arr.length == 7");
8} else if (arr.length < 7) {
9console.log("arr.length < 7");
10} else {
11console.log("arr.length > 7");
12}
1314
console.log("\nSwitch:");
15switch (arr.length) {
16case 7:
17console.log("arr.length == 7");
18break;
19case 6:
20console.log("arr.length == 6");
21break;
22default:
23console.log("arr.length != 6 and != 7");
24}
2526
switch ("foo") {
27case "bar":
28console.log("it's bar");
29break;
30case "foo":
31console.log("it's foo");
32break;
33default:
34console.log("not foo, not bar");
35}
3637
switch (1) { // Vergleich auf strikte Gleichheit (===)
38case "1":
39console.log("string(1)");
40break;
41case 1:
42console.log("number(1)");
43break;
44}
4546
47
48
console.log("\nContinue:");
49for (let i = 0; i < arr.length; i++) {
50const v = arr[i];
51if (v % 2 == 0) continue;
52console.log(v);
53}
5455
console.log("\nBreak with label:");
56outer: for (let i = 0; i < arr.length; i++) {
57for (let j = 0 ; j < i; j++) {
58if (j == 3) break outer;
59console.log(arr[i], arr[j]);
60}
61}
6263
console.log("\nin (properties of Arrays):");
64for (const key in arr) {
65console.log(key, arr[key]);
66}
6768
console.log("\nof (values of Arrays):");
69for (const value of arr) {
70console.log(value);
71}
7273
console.log("\nArray and Objects - instanceof:");
74console.log("arr instanceof Object", arr instanceof Object);
75console.log("arr instanceof Array", arr instanceof Array);
7677
const obj = {
78name: "John",
79age: 30,
80city: "Berlin"
81};
8283
console.log("\nin (properties of Objects):");
84for (const key in obj) {
85console.log(key, obj[key]);
86}
8788
/* TypeError: obj is not iterable
89for (const value of obj) {
90console.log(value);
91}
92*/
9394
95
{
96console.log("\nIteration über Iterables (here: Map):");
97const m = new Map();
98m.set("name", "Elisabeth");
99m.set("alter", 50);
100console.log("Properties of m: ");
101for (const key in m) {
102console.log(key, m[key]);
103}
104console.log("Values of m: ");
105for (const [key, value] of m) {
106console.log(key, value);
107}
108}
109110
{
111console.log("\nWhile Loop: ");
112let c = 0;
113while (c < arr.length) {
114const v = arr[c]
115if (v > 10) break;
116console.log(v);
117c++;
118}
119}
120121
122
{
123console.log("\nDo-While Loop: ");
124let c = 0
125do {
126console.log(arr[c]);
127c++;
128} while (c < arr.length);
129}
1// The last examples require that "use strict"; is not enabled!
23
// the function (see below) is hoisted, so it can be called before it is defined
4hello("Michael");
56
function hello(person = "World") {
7// argument with default value
8console.log(`fun: Hello ${person}!`);
9}
1011
// helloExpr(); // the variable declaration is hoisted, but not the definition!
12// So it cannot be called here!
13var helloExpr = function () {
14console.log("expr: Hello World!");
15};
1617
// Arrow Functions
18const times3 = (x) => x * 3;
19console.log("times3(5)", times3(5)); // 15
20const helloArrow = () => console.log("arrow: Hello World!");
21const helloBigArrow = () => {
22const s = "Hello World!";
23console.log("arrow: " + s);
24return s;
25};
2627
console.log("Hello World!");
28helloExpr();
29helloArrow();
3031
var helloXXX = function helloXXX() {
32// Function Expression with (useless) Name
33// console.log(arguments); // arguments is an array-like object
34console.log(`Hello: `, ...arguments);
35};
36helloXXX("Michael", "John", "Jane");
3738
function sum(...args) {
39// rest parameter
40console.log("args: " + args);
41process.stdout.write("...args: ");
42console.log(...args); // we use the spread operator here
43return args.reduce((a, b) => a + b, 0); // function nesting
44}
45console.log(sum(1, 2, 3, 4, 5)); // 15
46console.log(sum());
4748
/* Generator Functions */
49function* fib() {
50// generator
51let a = 0,
52b = 1;
53while (true) {
54yield a;
55[a, b] = [b, a + b];
56}
57}
58const fibGen = fib();
59console.log(fibGen.next().value); // 0
60console.log(fibGen.next().value); // 1
61console.log(fibGen.next().value); // 1
62console.log(fibGen.next().value); // 2
63/* Will cause an infinite loop: for (const i of fib()) console.log(i);
64// 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 ... */
6566
/** Partial function application */
6768
function add(x, y) {
69return x + y;
70}
7172
const add2 = add.bind(null, 2); // the "null" is the value of "this"
73console.log(add2(3));
7475
/** "this" in functions */
76console.log('"this" in functions:');
7778
function f(c) {
79const that = this;
8081
function f() {
82return this === that;
83}
8485
const fExpr = () => {
86return this === that;
87};
8889
console.log(" globalThis === that: " + (globalThis == this));
90console.log(" this === that (function): " + f());
91console.log(" this === that (function expression): " + fExpr());
92}
93f();
9495
globalThis.x = -1;
96this.x = 0;
97console.log(
98"this.x: " + this.x + "(globalThis === this: " + (globalThis === this) + ")",
99);
100101
function addToValue(b) {
102return this.x + b;
103}
104console.log(addToValue(1));
105console.log(addToValue.call(this, -101));
106107
const obj = { x: 101, addToValue: addToValue };
108console.log("obj.addtoValue(-101): " + obj.addToValue(-101));
109110
const add100 = addToValue.bind({ x: 100 });
111console.log("add100: " + add100(100));
112113
console.log("Done.");
1`use strict`;
23
// scope is limited to the enclosing function;
4// the definition is hoisted (initialized with undefined);
5// in modern JS, use let or const instead of var!
6var x = "x";
78
// scope is limited to the enclosing block;
9// reference before definition throws an error
10let y = "y";
1112
// scope is limited to the enclosing block
13const z = "z";
1415
16
function sumIfDefined(a, b) {
17if (parseInt(a)) {
18var result = parseInt(a); // don't do this in your real code!
19} else {
20result = 0;
21}
22const bVal = parseFloat(b);
23if (bVal) {
24result += bVal
25}
26return result;
27}
2829
console.log(sumIfDefined()); // 0
30console.log(sumIfDefined(1)); // 1
31console.log(sumIfDefined(1, 2)); // 3
32console.log(sumIfDefined(1, "2")); // 3
33console.log(sumIfDefined(undefined, "2")); // 2
3435
36
function global_x() {
37console.log(x,y);
3839
// const y = ''; // => the previous line throws an error because y is not defined
4041
console.log(x, y, z); // 1 2 3
42}
4344
function local_var_x() {
45console.log(x);
46// console.log(y); // y is not defined
4748
var x = 1; // the declaration of var is hoisted, but not the initialization
49let y = 2;
50const z = 3;
5152
console.log(x, y, z); // 1 2 3
53}
5455
56
console.log("Start:", x, y, z); // 0 0 0
57global_x();
58local_var_x();
5960
61
console.log("Last:", x, y, z); // 0 0 0
1let [a,b] = [1,2,3,4]; // array destructuring
2console.log(a,b); // 1
34
5
let {a : x, b : y} = {a: "a", b: "b"}; // object destructuring
6console.log(x,y); // 1
7let {a : u, b : v, ...w} = {a: "+", b: "-", c :"*", d:"/"}; // object destructuring
8console.log(u,v,w); // + - {c: "*", d: "/"}
910
let {k1 , k2} = {a: "a", b: "b"}; // object destructuring
11console.log(k1,k2); // undefined undefined // k1 and k2 are not defined in the object
1const someJSON = `{
2"name": "John",
3"age": 30,
4"cars": {
5"American": ["Ford"],
6"German": ["BMW", "Mercedes", "Audi"],
7"Italian": ["Fiat","Alfa Romeo", "Ferrari"]
8}
9}
10`
1112
const someObject = JSON.parse(someJSON);
13someObject.age = 31;
14someObject.cars.German.push("Porsche");
15someObject.cars.Italian.pop();
16console.log(someObject);
17console.log(JSON.stringify(someObject, null, 2));
Built-in support by means of regular expression literals and an API
Use Perl syntax
Methods on regular expression objects: test (e.g., RegExp.test(String)).
Methods on strings that take RegExps: search, match, replace, split,...
1{
2const p = /.*[1-9]+H/; // a regexp
3console.log(p.test("ad13H"));
4console.log(p.test("ad13"));
5console.log(p.test("13H"));
6}
78
{
9const p = /[1-9]+H/g;
10const s = "1H, 2H, 3P, 4C";
11console.log(s.match(p));
12console.log(s.replace(p, "XX"));
13}
this ist ein "zusätzlicher" Parameter, dessen Wert von der aufrufenden Form abhängt
this ermöglicht den Methoden den Zugriff auf ihr Objekt
this wird zum Zeitpunkt des Aufrufs gebunden (außer bei Arrow-Funktionen)
1//"use strict";
23
function counter () {
4// console.log(this === globalThis); // true
5if(this.count) // this is the global object if we don't use strict mode
6this.count ++;
7else {
8this.count = 1;
9}
1011
return this.count;
12}
1314
const counterExpr = function () {
15if(this.count)
16this.count ++;
17else {
18this.count = 1;
19}
2021
return this.count;
22}
2324
const counterArrow = () => {
25console.log(this);
26console.log(this === globalThis);
27this.count = this.count ? this.count + 1 : 1;
28return this.count;
29}
3031
console.log("\nCounter");
32console.log(counter()); // 1
33console.log(counter()); // 2
34console.log(`Counter (${globalThis.count})`);
3536
console.log("\nCounterExpression");
37console.log(counterExpr()); // 3
38console.log(counterExpr()); // 4
3940
console.log("\nCounter");
41const obj = {};
42console.log(counter.apply(obj)); // 1 - we set a new "this" object!
43console.log(counterExpr.apply(obj)); // 2
4445
console.log(`\nCounterArrow (${this.count})`);
46console.log(counterArrow.apply(obj)); // 1
47console.log(counterArrow.apply(undefined)); // 2
48console.log(counterArrow.apply()); // 3
49console.log(counterArrow.apply(obj)); // 4
50console.log(counterArrow.apply({})); // 5
5152
console.log("\nCounter (global)");
53console.log(counter());
54console.log(counterExpr());
1const p = { s : "p" };
2const c = Object.create(p);
3const gc = Object.create(c);
1const p = { s : "p" };
2const c = Object.create(p);
3const gc = Object.create(c);
4gc.t = "q";
Pseudoclassical Inheritance
1function Person(name, title){ this.name = name; this.title = title; } // constructor
2Person.prototype.formOfAddress = function (){
3const foa = "Dear ";
4if(this.title){ foa += this.title+" "; }
5return foa + this.name;
6}
7function Student(name, title, id, email) { // constructor
8Person.call(this, name, title);
9this.id = id;
10this.email = email;
11}
12Student.prototype = Object.create(Person.prototype);
13Student.prototype.constructor = Student;
1415
const aStudent = new Student("Emilia Galotti", "Mrs.", 1224441, 'emilia@galotti.com');
Objektabhängigkeiten
1function Person(name, title){ … }
2Person.prototype.formOfAddress = function (){ … }
34
function Student(name, title, id, email) { … }
5Student.prototype = Object.create(Person.prototype);
6Student.prototype.constructor = Student;
78
const p = new Person(…); const s = new Student(…);
1console.log({}.__proto__)
2console.log(Array.prototype)
3console.log(Array.prototype.__proto__)
4console.log(Array.prototype)
56
try {
7let a = [1];
8console.log(a.fold());
9} catch (error) {
10console.log("error: ", error.message)
11}
1213
// THIS IS NOT RECOMMENDED!
14// IF ECMAScript EVENTUALLY ADDS THIS FUNCTIONALITY,
15// IT MAY CAUSE HAVOC.
16Array.prototype.fold = function (f) {
17if (this.length === 0) {
18throw new Error("array is empty");
19} else if (this.length === 1) {
20return this[0];
21} else {
22let result = this[0];
23for (let i = 1; i < this.length; i++) {
24result = f(result, this[i]);
25}
26return result;
27}
28}
2930
let a = [1,10,100,1000];
31console.log(a.fold((a,b) => a + b));
3233
34
let o = { created : "long ago" };
35var p = Object.create(o);
36console.log(Object.getPrototypeOf(o));
37console.log(o.isPrototypeOf(p));
38console.log(Object.prototype.isPrototypeOf(p));
1class Figure {
2calcArea() {
3throw new Error('calcArea is not implemented');
4}
5}
6class Rectangle extends Figure {
7height;
8width;
910
constructor(height, width) {
11this.height = height;
12this.width = width;
13}
1415
calcArea() {
16return this.height * this.width;
17}
1819
get area() {
20return this.calcArea();
21}
2223
set area(value) {
24throw new Error('Area is read-only');
25}
26}
2728
const r = new Rectangle(10, 20);
29console.log("r instanceof Figure", r instanceof Figure); // true
30console.log(r.width);
31console.log(r.height);
32console.log(r.area); // 200
3334
try {
35r.area = 300; // Error: Area is read-only
36} catch (e) {
37console.log(e.message);
38}
3940
class Queue {
41#last = null;
42#first = null;
43constructor() { }
44enqueue(elem) {
45if (this.#first === null) {
46const c = { e: elem, next: null };
47this.#first = c
48this.#last = c
49} else {
50const c = { e: elem, next: null };
51this.#last.next = c;
52this.#last = c;
53}
54}
55dequeue() {
56if (this.#first === null) {
57return null;
58} else {
59const c = this.#first;
60this.#first = c.next;
61return c.e;
62}
63}
64isEmpty() {
65return this.#first === null;
66}
67}
1<html lang=en>
2<head>
3<meta charset="utf-8">
4<meta name="viewport" content="width=device-width, initial-scale=1.0">
5<title>DOM Manipulation with JavaScript</title>
6<script>
7function makeScriptsEditable() {
8const scripts = document.getElementsByTagName('script')
9for (const scriptElement of scripts) {
10scriptElement.contentEditable = true;
11scriptElement.style.display = 'block';
12scriptElement.style.whiteSpace = 'preserve';
13scriptElement.style.padding = '1em';
14scriptElement.style.backgroundColor = 'yellow';
15}
16}
17</script>
18</head>
19<body>
20<h1>DOM Manipulation with JavaScript</h1>
21<p id="demo">This is a paragraph.</p>
22<button type="button"
23onclick="
24document.getElementById('demo').style.color = 'red';
25makeScriptsEditable();">
26Magic!
27</button>
2829
<script>
30const demoElement = document.getElementById('demo');
31demoElement.addEventListener(
32'mouseover',
33() => demoElement.style.color = 'green'
34);
35demoElement.addEventListener(
36'mouseout',
37() => demoElement.style.color = 'unset'
38);
39</script>
4041
<p>Position der Mouse: <span id="position"></span></p>
42<script>
43window.addEventListener('mousemove', () => {
44document.getElementById('position').innerHTML =
45`(${event.clientX}, ${event.clientY})`;
46});
47</script>
4849
</body>
50</html>
1<html lang=en>
2<head>
3<meta charset="utf-8">
4<meta name="viewport" content="width=device-width, initial-scale=1.0">
5<title>Eventhandling</title>
6</head>
7<body>
89
10
<script>
11const box = document.getElementById('box');
12let color = 0;
13const setColor = () => {
14color = (color + 1) % 512 ;
15let rgb = color
16if (rgb > 255) rgb = 256-(rgb-255);
17// console.log(rgb);
18document.body.style.backgroundColor =
19`rgb(${rgb}, ${rgb}, ${rgb})`;
20};
21setInterval(setColor,10); // the function setColor is called every 10ms
2223
function getUsers() {
24fetch('http://127.0.0.1:4080/users')
25.then(response => response.json())
26.then(users => {
27const usersElement = document.getElementById('users');
28usersElement.innerText = JSON.stringify(users);
29});
30}
31</script>
3233
<div id=users> </div>
34<button onclick="getUsers()">Get Users</button>
35</body>
36</html>