9.2.0.5
Racket
jsmaker JavaScript Use Cases🔗ℹ
Hans Dijkema <hans@dijkewijk.nl>
This document describes the practical JavaScript use cases in
"demo/js-usecases.rkt". Each implementation is written as a Racket
snippet using js and is tested by compiling it to JavaScript and
executing that JavaScript with the configured test executor. The corresponding
tests are in "testing/jsmaker-usecases.rkt".
The examples are shown vertically: first the Racket/js-maker source, then the
generated JavaScript. Each code fragment is shown in a boxed documentation
cell, preserving the light shaded background of the earlier side-by-side
layout while avoiding narrow, wrapped code columns.
The tests intentionally use js/expression for their calls wherever
possible. Raw JavaScript remains only in small harness preambles, such as fake
setInterval, fake DOM objects, and fake fetch.
1 Running the examples🔗ℹ
Generate the JavaScript examples with:
| racket demo/js-usecases.rkt |
Run the use-case regression tests with:
| racket testing/jsmaker-usecases.rkt |
2.1 1. Random number between 1 and 5🔗ℹ
Racket / js-maker |
(js | (define (randomBetween1And5) | (return (+ (send Math floor (* (send Math random) 5)) 1)))) |
|
Generated JavaScript |
function randomBetween1And5() { | return (Math.floor((Math.random() * 5)) + 1); | } |
|
Tested behavior: With Math.random fixed at 0.80, the generated function returns 5.
2.2 2. Unique values with Set🔗ℹ
Racket / js-maker |
(js | (define (uniqueValues xs) | (return (send Array from (new Set xs))))) |
|
Generated JavaScript |
function uniqueValues(xs) { | return Array.from(new Set(xs)); | } |
|
Tested behavior: The array [1, 2, 2, 3, 1] becomes [1, 2, 3].
2.3 3. Six falsey JavaScript values🔗ℹ
Racket / js-maker |
(js | (define (falseyValues) | (return (array #f 0 "" js-null js-undefined js-NaN)))) |
|
Generated JavaScript |
function falseyValues() { | return [false, 0, "", null, undefined, NaN]; | } |
|
Tested behavior: Mapping JavaScript Boolean over the returned values yields six false values.
2.4 4. Currying🔗ℹ
Racket / js-maker |
(js | (define (add x) | (return (lambda (y) | (return (+ x y)))))) |
|
Generated JavaScript |
function add(x) { | return function(y) { | return (x + y); | }; | } |
|
Tested behavior: The generated call add(2)(3) returns 5; the test call itself is produced with js/expression.
2.5 5. Object destructuring🔗ℹ
Racket / js-maker |
(js | (define (describePerson person) | (let-object ([name 'name] | [age 'age 0]) | person | (return (string-append name ":" (number->string age)))))) |
|
Generated JavaScript |
function describePerson(person) { | return (() => { | const { name: name, age: age = 0 } = person; | return (name + ":" + String(age)); | })(); | } |
|
Tested behavior: The object { name: "Ada", age: 37 } is rendered as "Ada:37".
2.6 6. Escaping a timer interval🔗ℹ
Racket / js-maker |
(js | (define (startTimer) | (let* ([ticks 0] | [intervalId #f]) | (set! intervalId | (setInterval (lambda () | (set! ticks (+ ticks 1)) | (when (= ticks 3) | (clearInterval intervalId))) | 10)) | (return (object 'id intervalId | 'getTicks (lambda () (return ticks))))))) |
|
Generated JavaScript |
function startTimer() { | { | let ticks = 0; | let intervalId = false; | intervalId = setInterval(function() { | ticks = (ticks + 1); | if ((ticks === 3)) clearInterval(intervalId); | return undefined; | }, 10); | return {id: intervalId, getTicks: function() { return ticks; }}; | } | } |
|
Tested behavior: A fake timer runs the callback five times, but clearInterval stops it at tick 3.
2.7 7. Get, set, and delete object properties🔗ℹ
Racket / js-maker |
(js | (define (objectProps) | (let* ([obj (object 'a 1)] | [a1 obj.a] | [a2 (js-ref obj "a")]) | (let-object ([a3 'a]) obj | (set! obj.b 2) | (set-prop! obj "c" 3) | (delete-prop! obj "a") | (return (array a1 a2 a3 obj.b (js-ref obj "c") | (send Object hasOwn obj "a"))))))) |
|
Generated JavaScript |
function objectProps() { | let obj = {a: 1}; | let a1 = obj.a; | let a2 = obj["a"]; | return (() => { | const { a: a3 } = obj; | obj.b = 2; | obj["c"] = 3; | delete obj["a"]; | return [a1, a2, a3, obj.b, obj["c"], Object.hasOwn(obj, "a")]; | })(); | } |
|
Tested behavior: The three reads produce 1, the two writes produce 2 and 3, and the deleted property is absent.
2.8 8. String concatenation order🔗ℹ
Racket / js-maker |
(js | (define (concatOrder) | (return (array (+ 1 2 "3") | (+ "1" 2 3))))) |
|
Generated JavaScript |
function concatOrder() { | return [(1 + 2 + "3"), ("1" + 2 + 3)]; | } |
|
Tested behavior: The generated function returns ["33", "123"].
2.9 9. Object.freeze versus Object.seal🔗ℹ
Racket / js-maker |
(js | (define (freezeVsSeal) | (let* ([frozen (send Object freeze (object 'a 1))] | [sealed (send Object seal (object 'a 1))]) | (set! frozen.a 9) | (set! sealed.a 9) | (delete-prop! sealed "a") | (return (array frozen.a sealed.a | (send Object isFrozen frozen) | (send Object isSealed sealed) | (send Object hasOwn sealed "a")))))) |
|
Generated JavaScript |
function freezeVsSeal() { | let frozen = Object.freeze({a: 1}); | let sealed = Object.seal({a: 1}); | frozen.a = 9; | sealed.a = 9; | delete sealed["a"]; | return [frozen.a, sealed.a, Object.isFrozen(frozen), | Object.isSealed(sealed), Object.hasOwn(sealed, "a")]; | } |
|
Tested behavior: The frozen value stays 1; the sealed value changes to 9 but remains present.
2.10 10. Switch example🔗ℹ
Racket / js-maker |
(js | (define (switchExample n) | (case n | [(1) (return "one")] | [(2 3) (return "two-or-three")] | [else (return "other")])))) |
|
Generated JavaScript |
function switchExample(n) { | switch (n) { | case 1: return "one"; | case 2: | case 3: return "two-or-three"; | default: return "other"; | } | } |
|
Tested behavior: The generated function maps 1, 2, and 9 to the three expected branches.
2.11 11. Class constructor with a default value🔗ℹ
Racket / js-maker |
(js | (define-class Greeter | (constructor ([name "world"]) | (set! this.name name)) | (method greet () | (return (string-append "Hello " this.name)))) | | (define (classExample) | (let* ([a (new Greeter)] | [b (new Greeter "Ada")]) | (return (array (send a greet) (send b greet)))))) |
|
Generated JavaScript |
class Greeter { | constructor(name = "world") { | this.name = name; | } | greet() { | return ("Hello " + this.name); | } | } | function classExample() { | let a = new Greeter(); | let b = new Greeter("Ada"); | return [a.greet(), b.greet()]; | } |
|
Tested behavior: The default constructor value and explicit constructor argument both work.
2.12 12. Sort objects by a property🔗ℹ
Racket / js-maker |
(js | (define (sortByProperty xs prop) | (return (send (send xs slice) | sort | (lambda (a b) | (return (- (js-ref a prop) (js-ref b prop)))))))) |
|
Generated JavaScript |
function sortByProperty(xs, prop) { | return xs.slice().sort(function(a, b) { | return (a[prop] - b[prop]); | }); | } |
|
Tested behavior: Sorting age objects by age yields [20, 25, 30].
2.13 13. Four ways to delete or remove an array element🔗ℹ
Racket / js-maker |
(js | (define (deleteArrayWays xs) | (let* ([a1 (send xs slice)] | [a2 (send xs slice)] | [a3 (send xs slice)] | [a4 (send xs slice)]) | (send a1 splice 1 1) | (set! a2 (send a2 filter (lambda (x i) (return (not (= i 1)))))) | (set! a3 (send (send a3 slice 0 1) concat (send a3 slice 2))) | (delete-prop! a4 1) | (return (array a1 a2 a3 | (array (send Object hasOwn a4 "1") (length a4))))))) |
|
Generated JavaScript |
function deleteArrayWays(xs) { | let a1 = xs.slice(), a2 = xs.slice(), a3 = xs.slice(), a4 = xs.slice(); | a1.splice(1, 1); | a2 = a2.filter(function(x, i) { return !(i === 1); }); | a3 = a3.slice(0, 1).concat(a3.slice(2)); | delete a4[1]; | return [a1, a2, a3, [Object.hasOwn(a4, "1"), a4.length]]; | } |
|
Tested behavior: splice, filter, and slice/concat remove the item; delete leaves a hole and preserves length.
2.14 14. Bubble sort🔗ℹ
Racket / js-maker |
(js | (define (bubbleSort xs) | (let* ([a (send xs slice)] | [n (length a)]) | (while (> n 1) | (let* ([i 1]) | (while (< i n) | (when (> (list-ref a (- i 1)) (list-ref a i)) | (let* ([tmp (list-ref a (- i 1))]) | (vector-set! a (- i 1) (list-ref a i)) | (vector-set! a i tmp))) | (set! i (+ i 1)))) | (set! n (- n 1))) | (return a)))) |
|
Generated JavaScript |
function bubbleSort(xs) { | let a = xs.slice(); | let n = a.length; | while ((n > 1)) { | let i = 1; | while ((i < n)) { | if ((a[(i - 1)] > a[i])) { | let tmp = a[(i - 1)]; | a[(i - 1)] = a[i]; | a[i] = tmp; | } | i = (i + 1); | } | n = (n - 1); | } | return a; | } |
|
Tested behavior: Sorting [5, 1, 4, 2, 8] yields [1, 2, 4, 5, 8].
2.15 15. Recursive binary search🔗ℹ
Racket / js-maker |
(js | (define (binarySearch xs target low high) | (if (> low high) | (return -1) | (let* ([mid (send Math floor (/ (+ low high) 2))] | [value (list-ref xs mid)]) | (cond | [(= value target) (return mid)] | [(< value target) (return (binarySearch xs target (+ mid 1) high))] | [else (return (binarySearch xs target low (- mid 1)))]))))) |
|
Generated JavaScript |
function binarySearch(xs, target, low, high) { | if ((low > high)) return -1; | let mid = Math.floor(((low + high) / 2)); | let value = xs[mid]; | if ((value === target)) return mid; | if ((value < target)) return binarySearch(xs, target, (mid + 1), high); | return binarySearch(xs, target, low, (mid - 1)); | } |
|
Tested behavior: Searching 7 returns index 3; searching 4 returns -1.
2.16 16. Count occurrences with Map🔗ℹ
Racket / js-maker |
(js | (define (countOccurrences xs) | (let* ([counts (new Map)]) | (for ([x (in-list xs)]) | (if (send counts has x) | (send counts set x (+ (send counts get x) 1)) | (send counts set x 1))) | (return (send Array from (send counts entries)))))) |
|
Generated JavaScript |
function countOccurrences(xs) { | let counts = new Map(); | for (const x of xs) { | if (counts.has(x)) counts.set(x, (counts.get(x) + 1)); | else counts.set(x, 1); | } | return Array.from(counts.entries()); | } |
|
Tested behavior: The array ["a", "b", "a", "c", "b", "a"] yields [["a",3],["b",2],["c",1]].
2.17 17. Get HTML in three ways🔗ℹ
Racket / js-maker |
(js | (define (getHtmlThreeWays) | (return (array document.body.innerHTML | (js-dot (send document querySelector "body") innerHTML) | (js-ref (send document getElementById "root") "innerHTML"))))) |
|
Generated JavaScript |
function getHtmlThreeWays() { | return [document.body.innerHTML, | document.querySelector("body").innerHTML, | document.getElementById("root")["innerHTML"]]; | } |
|
Tested behavior: A fake DOM returns the same HTML string through all three access forms.
2.18 18. Anagram / rearrangement check🔗ℹ
Racket / js-maker |
(js | (define (sortChars s) | (return (send (send (send s split "") sort) join ""))) | | (define (canArrange stringA stringB) | (return (string=? (sortChars stringA) (sortChars stringB))))) |
|
Generated JavaScript |
function sortChars(s) { | return s.split("").sort().join(""); | } | function canArrange(stringA, stringB) { | return (sortChars(stringA) === sortChars(stringB)); | } |
|
Tested behavior: listen/silent returns true; abc/abd returns false.
2.19 19. Pairs equal to a target, without repeats🔗ℹ
Racket / js-maker |
(js | (define (pairsEqualTarget xs target) | (let* ([seen (new Set)] | [used (new Set)] | [out (array)]) | (for ([x (in-list xs)]) | (let* ([y (- target x)]) | (if (and (send seen has y) | (not (send used has x)) | (not (send used has y))) | (begin | (send out push (array y x)) | (send used add x) | (send used add y)) | (send seen add x)))) | (return out)))) |
|
Generated JavaScript |
function pairsEqualTarget(xs, target) { | let seen = new Set(); | let used = new Set(); | let out = []; | for (const x of xs) { | let y = (target - x); | if (seen.has(y) && !(used.has(x)) && !(used.has(y))) { | out.push([y, x]); used.add(x); used.add(y); | } else { | seen.add(x); | } | } | return out; | } |
|
Tested behavior: For [1, 2, 3, 4, 3, 5] and target 6 the returned pairs are [[2,4],[3,3],[1,5]].
2.20 20. Fetch API with result and error handling🔗ℹ
Racket / js-maker |
(js | (define (loadTitle url) | (return | (send | (send | (send (fetch url) | then | (lambda (response) | (return (send response json)))) | then | (lambda (data) | (return (object 'ok #t 'title data.title)))) | catch | (lambda (err) | (return (object 'ok #f 'message err.message))))))) |
|
Generated JavaScript |
function loadTitle(url) { | return fetch(url) | .then(function(response) { return response.json(); }) | .then(function(data) { return {ok: true, title: data.title}; }) | .catch(function(err) { return {ok: false, message: err.message}; }); | } |
|
Tested behavior: A fake fetch resolves /ok to {ok:true,title:"Done"} and rejects /fail to {ok:false,message:"network"}.