├── html ├── .keep ├── code ├── img ├── empty.html ├── example │ ├── data.txt │ ├── muriel.json │ ├── bert.json │ ├── fruit.json │ ├── suzie.json │ ├── fruit.xml │ ├── submit.html │ └── message.html ├── og.jpg ├── favicon.ico ├── font │ ├── pt_mono.woff │ └── cinzel_bold.woff ├── author.txt ├── author.json ├── css │ ├── paint.css │ └── game.css ├── author.html └── errata.html ├── code ├── chapter │ ├── .keep │ └── 22_fast.js ├── skillsharing │ ├── .keep │ ├── public │ │ └── skillsharing.css │ └── package.json ├── hello.js ├── squareworker.js ├── solutions │ ├── 02_1_looping_a_triangle.js │ ├── 20_3_a_public_space_on_the_web │ │ ├── other.html │ │ ├── index.html │ │ └── public_space.js │ ├── 05_1_flattening.js │ ├── 06_4_borrowing_a_method.js │ ├── 03_1_minimum.js │ ├── 02_2_fizzbuzz.js │ ├── 09_2_quoting_style.js │ ├── 05_2_your_own_loop.js │ ├── 02_3_chessboard.js │ ├── 03_2_recursion.js │ ├── 12_3_comments.js │ ├── 03_3_bean_counting.js │ ├── 18_1_content_negotiation.js │ ├── 05_3_everything.js │ ├── 12_1_arrays.js │ ├── 20_1_search_tool.mjs │ ├── 22_1_prime_numbers.js │ ├── 05_4_dominant_writing_direction.js │ ├── 08_1_retry.js │ ├── 09_3_numbers_again.js │ ├── 10_2_roads_module.js │ ├── 18_2_a_javascript_workbench.html │ ├── 22_1_pathfinding.js │ ├── 11_1_quiet_times.js │ ├── 06_1_a_vector_type.js │ ├── 20_2_directory_creation.mjs │ ├── 04_1_the_sum_of_a_range.js │ ├── 22_2_timing.js │ ├── 11_2_real_promises.js │ ├── 22_2_faster_prime_numbers.js │ ├── 04_2_reversing_an_array.js │ ├── 11_1_tracking_the_scalpel.js │ ├── 04_4_deep_comparison.js │ ├── 12_4_fixing_scope.js │ ├── 06_2_groups.js │ ├── 07_3_persistent_group.js │ ├── 07_1_measuring_a_robot.js │ ├── 15_1_balloon.html │ ├── 08_2_the_locked_box.js │ ├── 21_1_disk_persistence.mjs │ ├── 15_2_mouse_trail.html │ ├── 16_1_game_over.html │ ├── 14_3_the_cats_hat.html │ ├── 04_3_a_list.js │ ├── 14_2_elements_by_tag_name.html │ ├── 07_2_robot_efficiency.js │ ├── 17_3_a_bouncing_ball.html │ ├── 11_3_building_promiseall.js │ ├── 15_3_tabs.html │ ├── 06_3_iterable_groups.js │ ├── 19_3_circles.html │ ├── 09_1_regexp_golf.js │ ├── 19_2_efficient_drawing.html │ ├── 22_3_optimizing.js │ ├── 17_2_the_pie_chart.html │ ├── 19_4_proper_lines.html │ ├── 14_1_build_a_table.html │ ├── 19_1_keyboard_bindings.html │ ├── 17_1_shapes.html │ ├── 16_3_a_monster.html │ ├── 21_2_comment_field_resets.mjs │ ├── 18_3_conways_game_of_life.html │ └── 16_2_pausing_the_game.html ├── stop_keys.js ├── load.js ├── intro.js ├── LICENSE ├── index.html ├── draw_layout.js └── animatevillage.js ├── epub ├── mimetype ├── font │ ├── pt_mono.otf │ └── cinzel_bold.otf ├── META-INF │ └── container.xml ├── titlepage.xhtml ├── frontmatter.xhtml ├── style.css ├── toc.xhtml.src └── content.opf.src ├── src ├── require.js ├── client │ ├── index.mjs │ ├── rollup.config.mjs │ └── editor.mjs ├── epub_chapter.html ├── check_links.mjs ├── extract_hints.mjs ├── generate_epub_toc.mjs ├── add_images_to_epub.mjs ├── build_code.mjs ├── chapter.html ├── varify.mjs ├── pseudo_json.mjs └── transform.mjs ├── book.pdf ├── book.epub ├── book.mobi ├── img ├── cat.png ├── hat.png ├── cover.jpg ├── tamil.png ├── boxed-in.png ├── darkblue.png ├── display.png ├── drag-bar.png ├── object.jpg ├── ostrich.png ├── parcel2x.png ├── player.png ├── prompt.png ├── sprites.png ├── svg-demo.png ├── village.png ├── blockquote.png ├── help-field.png ├── holberton.png ├── home-page.png ├── player_big.png ├── robot_idle.png ├── tree_graph.png ├── village2x.png ├── canvas_circle.png ├── canvas_fill.png ├── canvas_game.png ├── canvas_path.png ├── canvas_scale.png ├── canvas_stroke.png ├── canvas_tree.png ├── cat-animation.png ├── color-field.png ├── colored-links.png ├── form_fields.png ├── form_select.png ├── highlighted.png ├── nextjournal.png ├── object_full.jpg ├── pixel_editor.png ├── robot_idle2x.png ├── robot_moving.gif ├── skillsharing.png ├── sprites_big.png ├── weresquirrel.png ├── Hieres-sur-Amby.png ├── button_disabled.png ├── canvas_triangle.png ├── exercise_shapes.png ├── robot_moving2x.gif ├── canvas_beziercurve.png ├── canvas_pie_chart.png ├── chapter_picture_00.jpg ├── chapter_picture_1.jpg ├── chapter_picture_10.jpg ├── chapter_picture_11.jpg ├── chapter_picture_12.jpg ├── chapter_picture_13.jpg ├── chapter_picture_14.jpg ├── chapter_picture_15.jpg ├── chapter_picture_16.jpg ├── chapter_picture_17.jpg ├── chapter_picture_18.jpg ├── chapter_picture_19.jpg ├── chapter_picture_2.jpg ├── chapter_picture_20.jpg ├── chapter_picture_21.jpg ├── chapter_picture_3.jpg ├── chapter_picture_4.jpg ├── chapter_picture_5.jpg ├── chapter_picture_6.jpg ├── chapter_picture_7.jpg ├── chapter_picture_8.jpg ├── chapter_picture_9.jpg ├── game_simpleLevel.png ├── middle_east_graph.png ├── canvas_quadraticcurve.png ├── middle_east_graph_random.png ├── game-grid.svg ├── linked-list.svg ├── mirror.svg ├── html-boxes.svg ├── cos_sin.svg ├── rabbits.svg ├── control-io.svg ├── transform.svg ├── controlflow-straight.svg ├── re_pigchickens.svg ├── html-links.svg ├── pizza-squirrel.svg ├── syntax_tree.svg ├── flood-grid.svg ├── line-grid.svg ├── controlflow-loop.svg └── re_number.svg ├── book_mobile.pdf ├── pdf ├── build.sh └── book.tex ├── .gitignore ├── package.json ├── README.md └── Makefile /html/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/chapter/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /html/code: -------------------------------------------------------------------------------- 1 | ../code -------------------------------------------------------------------------------- /html/img: -------------------------------------------------------------------------------- 1 | ../img/ -------------------------------------------------------------------------------- /code/skillsharing/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /epub/mimetype: -------------------------------------------------------------------------------- 1 | application/epub+zip -------------------------------------------------------------------------------- /code/hello.js: -------------------------------------------------------------------------------- 1 | alert("hello!"); 2 | -------------------------------------------------------------------------------- /src/require.js: -------------------------------------------------------------------------------- 1 | module.exports = require 2 | -------------------------------------------------------------------------------- /html/empty.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /html/example/data.txt: -------------------------------------------------------------------------------- 1 | This is the content of data.txt 2 | -------------------------------------------------------------------------------- /html/example/muriel.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Muriel" 3 | } 4 | -------------------------------------------------------------------------------- /src/client/index.mjs: -------------------------------------------------------------------------------- 1 | import "./ejs.mjs" 2 | import "./code.mjs" 3 | -------------------------------------------------------------------------------- /book.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/book.pdf -------------------------------------------------------------------------------- /book.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/book.epub -------------------------------------------------------------------------------- /book.mobi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/book.mobi -------------------------------------------------------------------------------- /html/og.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/html/og.jpg -------------------------------------------------------------------------------- /img/cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/cat.png -------------------------------------------------------------------------------- /img/hat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/hat.png -------------------------------------------------------------------------------- /html/example/bert.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bert", 3 | "spouse": "example/suzie.json" 4 | } 5 | -------------------------------------------------------------------------------- /img/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/cover.jpg -------------------------------------------------------------------------------- /img/tamil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/tamil.png -------------------------------------------------------------------------------- /book_mobile.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/book_mobile.pdf -------------------------------------------------------------------------------- /html/example/fruit.json: -------------------------------------------------------------------------------- 1 | {"banana": "yellow", 2 | "lemon": "yellow", 3 | "cherry": "red"} 4 | -------------------------------------------------------------------------------- /html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/html/favicon.ico -------------------------------------------------------------------------------- /img/boxed-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/boxed-in.png -------------------------------------------------------------------------------- /img/darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/darkblue.png -------------------------------------------------------------------------------- /img/display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/display.png -------------------------------------------------------------------------------- /img/drag-bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/drag-bar.png -------------------------------------------------------------------------------- /img/object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/object.jpg -------------------------------------------------------------------------------- /img/ostrich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/ostrich.png -------------------------------------------------------------------------------- /img/parcel2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/parcel2x.png -------------------------------------------------------------------------------- /img/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/player.png -------------------------------------------------------------------------------- /img/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/prompt.png -------------------------------------------------------------------------------- /img/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/sprites.png -------------------------------------------------------------------------------- /img/svg-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/svg-demo.png -------------------------------------------------------------------------------- /img/village.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/village.png -------------------------------------------------------------------------------- /img/blockquote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/blockquote.png -------------------------------------------------------------------------------- /img/help-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/help-field.png -------------------------------------------------------------------------------- /img/holberton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/holberton.png -------------------------------------------------------------------------------- /img/home-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/home-page.png -------------------------------------------------------------------------------- /img/player_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/player_big.png -------------------------------------------------------------------------------- /img/robot_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/robot_idle.png -------------------------------------------------------------------------------- /img/tree_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/tree_graph.png -------------------------------------------------------------------------------- /img/village2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/village2x.png -------------------------------------------------------------------------------- /epub/font/pt_mono.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/epub/font/pt_mono.otf -------------------------------------------------------------------------------- /img/canvas_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_circle.png -------------------------------------------------------------------------------- /img/canvas_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_fill.png -------------------------------------------------------------------------------- /img/canvas_game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_game.png -------------------------------------------------------------------------------- /img/canvas_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_path.png -------------------------------------------------------------------------------- /img/canvas_scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_scale.png -------------------------------------------------------------------------------- /img/canvas_stroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_stroke.png -------------------------------------------------------------------------------- /img/canvas_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_tree.png -------------------------------------------------------------------------------- /img/cat-animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/cat-animation.png -------------------------------------------------------------------------------- /img/color-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/color-field.png -------------------------------------------------------------------------------- /img/colored-links.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/colored-links.png -------------------------------------------------------------------------------- /img/form_fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/form_fields.png -------------------------------------------------------------------------------- /img/form_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/form_select.png -------------------------------------------------------------------------------- /img/highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/highlighted.png -------------------------------------------------------------------------------- /img/nextjournal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/nextjournal.png -------------------------------------------------------------------------------- /img/object_full.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/object_full.jpg -------------------------------------------------------------------------------- /img/pixel_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/pixel_editor.png -------------------------------------------------------------------------------- /img/robot_idle2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/robot_idle2x.png -------------------------------------------------------------------------------- /img/robot_moving.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/robot_moving.gif -------------------------------------------------------------------------------- /img/skillsharing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/skillsharing.png -------------------------------------------------------------------------------- /img/sprites_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/sprites_big.png -------------------------------------------------------------------------------- /img/weresquirrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/weresquirrel.png -------------------------------------------------------------------------------- /html/font/pt_mono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/html/font/pt_mono.woff -------------------------------------------------------------------------------- /img/Hieres-sur-Amby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/Hieres-sur-Amby.png -------------------------------------------------------------------------------- /img/button_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/button_disabled.png -------------------------------------------------------------------------------- /img/canvas_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_triangle.png -------------------------------------------------------------------------------- /img/exercise_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/exercise_shapes.png -------------------------------------------------------------------------------- /img/robot_moving2x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/robot_moving2x.gif -------------------------------------------------------------------------------- /code/squareworker.js: -------------------------------------------------------------------------------- 1 | addEventListener("message", event => { 2 | postMessage(event.data * event.data); 3 | }); 4 | -------------------------------------------------------------------------------- /epub/font/cinzel_bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/epub/font/cinzel_bold.otf -------------------------------------------------------------------------------- /html/font/cinzel_bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/html/font/cinzel_bold.woff -------------------------------------------------------------------------------- /img/canvas_beziercurve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_beziercurve.png -------------------------------------------------------------------------------- /img/canvas_pie_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_pie_chart.png -------------------------------------------------------------------------------- /img/chapter_picture_00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_00.jpg -------------------------------------------------------------------------------- /img/chapter_picture_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_1.jpg -------------------------------------------------------------------------------- /img/chapter_picture_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_10.jpg -------------------------------------------------------------------------------- /img/chapter_picture_11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_11.jpg -------------------------------------------------------------------------------- /img/chapter_picture_12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_12.jpg -------------------------------------------------------------------------------- /img/chapter_picture_13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_13.jpg -------------------------------------------------------------------------------- /img/chapter_picture_14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_14.jpg -------------------------------------------------------------------------------- /img/chapter_picture_15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_15.jpg -------------------------------------------------------------------------------- /img/chapter_picture_16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_16.jpg -------------------------------------------------------------------------------- /img/chapter_picture_17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_17.jpg -------------------------------------------------------------------------------- /img/chapter_picture_18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_18.jpg -------------------------------------------------------------------------------- /img/chapter_picture_19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_19.jpg -------------------------------------------------------------------------------- /img/chapter_picture_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_2.jpg -------------------------------------------------------------------------------- /img/chapter_picture_20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_20.jpg -------------------------------------------------------------------------------- /img/chapter_picture_21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_21.jpg -------------------------------------------------------------------------------- /img/chapter_picture_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_3.jpg -------------------------------------------------------------------------------- /img/chapter_picture_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_4.jpg -------------------------------------------------------------------------------- /img/chapter_picture_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_5.jpg -------------------------------------------------------------------------------- /img/chapter_picture_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_6.jpg -------------------------------------------------------------------------------- /img/chapter_picture_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_7.jpg -------------------------------------------------------------------------------- /img/chapter_picture_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_8.jpg -------------------------------------------------------------------------------- /img/chapter_picture_9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/chapter_picture_9.jpg -------------------------------------------------------------------------------- /img/game_simpleLevel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/game_simpleLevel.png -------------------------------------------------------------------------------- /img/middle_east_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/middle_east_graph.png -------------------------------------------------------------------------------- /code/solutions/02_1_looping_a_triangle.js: -------------------------------------------------------------------------------- 1 | for (let line = "#"; line.length < 8; line += "#") 2 | console.log(line); 3 | -------------------------------------------------------------------------------- /img/canvas_quadraticcurve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/canvas_quadraticcurve.png -------------------------------------------------------------------------------- /html/example/suzie.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Suzie", 3 | "spouse": "example/bert.json", 4 | "mother": "example/muriel.json" 5 | } 6 | -------------------------------------------------------------------------------- /img/middle_east_graph_random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/eloquent-javascript-es/main/img/middle_east_graph_random.png -------------------------------------------------------------------------------- /code/stop_keys.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("keydown", e => { 2 | if (/Arrow|Home|End|Page/.test(e.key)) e.preventDefault() 3 | }) 4 | -------------------------------------------------------------------------------- /code/solutions/20_3_a_public_space_on_the_web/other.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
Marijn Haverbeke, Programmer
6 | 7 |You can reach me at marijn@haverbeke.nl, or visit my web page, marijnhaverbeke.nl.
10 |This is a self-editing website. Select a file, edit it, and save to 7 | update the website.
8 | 9 |Files:
10 | 11 |
12 |
13 |
14 |
15 |
14 | You submitted...
7 | 8 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /code/solutions/22_1_pathfinding.js: -------------------------------------------------------------------------------- 1 | function findPath(a, b) { 2 | let work = [[a]]; 3 | for (let path of work) { 4 | let end = path[path.length - 1]; 5 | if (end == b) return path; 6 | for (let next of end.edges) { 7 | if (!work.some(path => path[path.length - 1] == next)) { 8 | work.push(path.concat([next])); 9 | } 10 | } 11 | } 12 | } 13 | 14 | let graph = treeGraph(4, 4); 15 | let root = graph[0], leaf = graph[graph.length - 1]; 16 | console.log(findPath(root, leaf).length); 17 | // → 4 18 | 19 | leaf.connect(root); 20 | console.log(findPath(root, leaf).length); 21 | // → 2 22 | -------------------------------------------------------------------------------- /code/solutions/11_1_quiet_times.js: -------------------------------------------------------------------------------- 1 | async function activityTable(day) { 2 | let table = []; 3 | for (let i = 0; i < 24; i++) table[i] = 0; 4 | 5 | let logFileList = await textFile("camera_logs.txt"); 6 | for (let filename of logFileList.split("\n")) { 7 | let log = await textFile(filename); 8 | for (let timestamp of log.split("\n")) { 9 | let date = new Date(Number(timestamp)); 10 | if (date.getDay() == day) { 11 | table[date.getHours()]++; 12 | } 13 | } 14 | } 15 | 16 | return table; 17 | } 18 | 19 | activityTable(1) 20 | .then(table => console.log(activityGraph(table))); 21 | -------------------------------------------------------------------------------- /code/intro.js: -------------------------------------------------------------------------------- 1 | function rango(start, end, step) { 2 | if (step == null) step = 1; 3 | var array = []; 4 | 5 | if (step > 0) { 6 | for (var i = start; i <= end; i += step) 7 | array.push(i); 8 | } else { 9 | for (var i = start; i >= end; i += step) 10 | array.push(i); 11 | } 12 | return array; 13 | } 14 | 15 | function suma(array) { 16 | var total = 0; 17 | for (var i = 0; i < array.length; i++) 18 | total += array[i]; 19 | return total; 20 | } 21 | 22 | function factorial(n) { 23 | if (n == 0) { 24 | return 1; 25 | } else { 26 | return factorial(n - 1) * n; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/solutions/06_1_a_vector_type.js: -------------------------------------------------------------------------------- 1 | class Vec { 2 | constructor(x, y) { 3 | this.x = x; 4 | this.y = y; 5 | } 6 | 7 | plus(other) { 8 | return new Vec(this.x + other.x, this.y + other.y); 9 | } 10 | 11 | minus(other) { 12 | return new Vec(this.x - other.x, this.y - other.y); 13 | } 14 | 15 | get length() { 16 | return Math.sqrt(this.x * this.x + this.y * this.y); 17 | } 18 | } 19 | 20 | console.log(new Vec(1, 2).plus(new Vec(2, 3))); 21 | // → Vec{x: 3, y: 5} 22 | console.log(new Vec(1, 2).minus(new Vec(2, 3))); 23 | // → Vec{x: -1, y: -1} 24 | console.log(new Vec(3, 4).length); 25 | // → 5 26 | -------------------------------------------------------------------------------- /code/solutions/20_2_directory_creation.mjs: -------------------------------------------------------------------------------- 1 | // This code won't work on its own, but is also included in the 2 | // code/file_server.js file, which defines the whole system. 3 | 4 | import {mkdir} from "node:fs/promises"; 5 | 6 | methods.MKCOL = async function(request) { 7 | let path = urlPath(request.url); 8 | let stats; 9 | try { 10 | stats = await stat(path); 11 | } catch (error) { 12 | if (error.code != "ENOENT") throw error; 13 | await mkdir(path); 14 | return {status: 204}; 15 | } 16 | if (stats.isDirectory()) return {status: 204}; 17 | else return {status: 400, body: "Not a directory"}; 18 | }; 19 | -------------------------------------------------------------------------------- /code/solutions/04_1_the_sum_of_a_range.js: -------------------------------------------------------------------------------- 1 | function range(start, end, step = start < end ? 1 : -1) { 2 | let array = []; 3 | 4 | if (step > 0) { 5 | for (let i = start; i <= end; i += step) array.push(i); 6 | } else { 7 | for (let i = start; i >= end; i += step) array.push(i); 8 | } 9 | return array; 10 | } 11 | 12 | function sum(array) { 13 | let total = 0; 14 | for (let value of array) { 15 | total += value; 16 | } 17 | return total; 18 | } 19 | 20 | console.log(range(1, 10)) 21 | // → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 22 | console.log(range(5, 2, -1)); 23 | // → [5, 4, 3, 2] 24 | console.log(sum(range(1, 10))); 25 | // → 55 26 | -------------------------------------------------------------------------------- /code/solutions/22_2_timing.js: -------------------------------------------------------------------------------- 1 | function findPath(a, b) { 2 | let work = [[a]]; 3 | for (let path of work) { 4 | let end = path[path.length - 1]; 5 | if (end == b) return path; 6 | for (let next of end.edges) { 7 | if (!work.some(path => path[path.length - 1] == next)) { 8 | work.push(path.concat([next])); 9 | } 10 | } 11 | } 12 | } 13 | 14 | function time(findPath) { 15 | let graph = treeGraph(6, 6); 16 | let startTime = Date.now(); 17 | let result = findPath(graph[0], graph[graph.length - 1]); 18 | console.log(`Path with length ${result.length} found in ${Date.now() - startTime}ms`); 19 | } 20 | time(findPath); 21 | -------------------------------------------------------------------------------- /code/solutions/11_2_real_promises.js: -------------------------------------------------------------------------------- 1 | function activityTable(day) { 2 | let table = []; 3 | for (let i = 0; i < 24; i++) table[i] = 0; 4 | 5 | return textFile("camera_logs.txt").then(files => { 6 | return Promise.all(files.split("\n").map(name => { 7 | return textFile(name).then(log => { 8 | for (let timestamp of log.split("\n")) { 9 | let date = new Date(Number(timestamp)); 10 | if (date.getDay() == day) { 11 | table[date.getHours()]++; 12 | } 13 | } 14 | }); 15 | })); 16 | }).then(() => table); 17 | } 18 | 19 | activityTable(6) 20 | .then(table => console.log(activityGraph(table))); 21 | -------------------------------------------------------------------------------- /code/solutions/22_2_faster_prime_numbers.js: -------------------------------------------------------------------------------- 1 | function* primes() { 2 | let found = []; 3 | for (let n = 2;; n++) { 4 | let skip = false, root = Math.sqrt(n); 5 | for (let prev of found) { 6 | if (prev > root) { 7 | break; 8 | } else if (n % prev == 0) { 9 | skip = true; 10 | break; 11 | } 12 | } 13 | if (!skip) { 14 | found.push(n); 15 | yield n; 16 | } 17 | } 18 | } 19 | 20 | function measurePrimes() { 21 | let iter = primes(), t0 = Date.now(); 22 | for (let i = 0; i < 10000; i++) { 23 | iter.next(); 24 | } 25 | console.log(`Took ${Date.now() - t0}ms`); 26 | } 27 | 28 | measurePrimes(); 29 | -------------------------------------------------------------------------------- /code/solutions/04_2_reversing_an_array.js: -------------------------------------------------------------------------------- 1 | function reverseArray(array) { 2 | let output = []; 3 | for (let i = array.length - 1; i >= 0; i--) { 4 | output.push(array[i]); 5 | } 6 | return output; 7 | } 8 | 9 | function reverseArrayInPlace(array) { 10 | for (let i = 0; i < Math.floor(array.length / 2); i++) { 11 | let old = array[i]; 12 | array[i] = array[array.length - 1 - i]; 13 | array[array.length - 1 - i] = old; 14 | } 15 | return array; 16 | } 17 | 18 | console.log(reverseArray(["A", "B", "C"])); 19 | // → ["C", "B", "A"]; 20 | let arrayValue = [1, 2, 3, 4, 5]; 21 | reverseArrayInPlace(arrayValue); 22 | console.log(arrayValue); 23 | // → [5, 4, 3, 2, 1] 24 | -------------------------------------------------------------------------------- /code/solutions/11_1_tracking_the_scalpel.js: -------------------------------------------------------------------------------- 1 | async function locateScalpel(nest) { 2 | let current = nest.name; 3 | for (;;) { 4 | let next = await anyStorage(nest, current, "scalpel"); 5 | if (next == current) return current; 6 | current = next; 7 | } 8 | } 9 | 10 | function locateScalpel2(nest) { 11 | function loop(current) { 12 | return anyStorage(nest, current, "scalpel").then(next => { 13 | if (next == current) return current; 14 | else return loop(next); 15 | }); 16 | } 17 | return loop(nest.name); 18 | } 19 | 20 | locateScalpel(bigOak).then(console.log); 21 | // → Butcher's Shop 22 | locateScalpel2(bigOak).then(console.log); 23 | // → Butcher's Shop 24 | -------------------------------------------------------------------------------- /html/css/game.css: -------------------------------------------------------------------------------- 1 | .background { background: rgb(52, 166, 251); 2 | table-layout: fixed; 3 | border-spacing: 0; } 4 | .background td { padding: 0; } 5 | .lava { background: rgb(255, 100, 100); } 6 | .wall { background: white; } 7 | 8 | .actor { position: absolute; } 9 | .coin { background: rgb(241, 229, 89); } 10 | .player { background: rgb(64, 64, 64); } 11 | 12 | .game { 13 | overflow: hidden; 14 | max-width: 600px; 15 | max-height: 450px; 16 | position: relative; 17 | } 18 | 19 | .lost .player { 20 | background: rgb(160, 64, 64); 21 | } 22 | .won .player { 23 | box-shadow: -4px -7px 8px white, 4px -7px 8px white; 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /nostarch/[012]*.tex 2 | /nostarch/hints.tex 3 | /nostarch/book.* 4 | /nostarch.pdf 5 | /pdf/[012]*.tex 6 | /pdf/hints.tex 7 | /pdf/book.aux 8 | /pdf/book.idx 9 | /pdf/book.ilg 10 | /pdf/book.ind 11 | /pdf/book.log 12 | /pdf/book.toc 13 | /pdf/book_mobile.* 14 | /pdf/*.log 15 | /code/chapter/* 16 | /code/chapter_info.js 17 | /code/file_server.mjs 18 | /code/skillsharing.zip 19 | /code/solutions/20_3_a_public_space_on_the_web.zip 20 | /code/skillsharing/* 21 | /node_modules 22 | .tern-port 23 | /toc.txt 24 | /img/cover.xcf 25 | /img/generated/* 26 | /epub/[012]*.xhtml 27 | /epub/hints.xhtml 28 | /epub/img/* 29 | /epub/content.opf 30 | /epub/toc.xhtml 31 | /scripts 32 | .DS_Store 33 | package-lock.json 34 | pnpm-lock.yaml -------------------------------------------------------------------------------- /code/solutions/04_4_deep_comparison.js: -------------------------------------------------------------------------------- 1 | function deepEqual(a, b) { 2 | if (a === b) return true; 3 | 4 | if (a == null || typeof a != "object" || 5 | b == null || typeof b != "object") return false; 6 | 7 | let keysA = Object.keys(a), keysB = Object.keys(b); 8 | 9 | if (keysA.length != keysB.length) return false; 10 | 11 | for (let key of keysA) { 12 | if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false; 13 | } 14 | 15 | return true; 16 | } 17 | 18 | let obj = {here: {is: "an"}, object: 2}; 19 | console.log(deepEqual(obj, obj)); 20 | // → true 21 | console.log(deepEqual(obj, {here: 1, object: 2})); 22 | // → false 23 | console.log(deepEqual(obj, {here: {is: "an"}, object: 2})); 24 | // → true 25 | -------------------------------------------------------------------------------- /code/solutions/12_4_fixing_scope.js: -------------------------------------------------------------------------------- 1 | specialForms.set = (args, env) => { 2 | if (args.length != 2 || args[0].type != "word") { 3 | throw new SyntaxError("Bad use of set"); 4 | } 5 | let varName = args[0].name; 6 | let value = evaluate(args[1], env); 7 | 8 | for (let scope = env; scope; scope = Object.getPrototypeOf(scope)) { 9 | if (Object.hasOwn(scope, varName)) { 10 | scope[varName] = value; 11 | return value; 12 | } 13 | } 14 | throw new ReferenceError(`Setting undefined variable ${varName}`); 15 | }; 16 | 17 | run(` 18 | do(define(x, 4), 19 | define(setx, fun(val, set(x, val))), 20 | setx(50), 21 | print(x)) 22 | `); 23 | // → 50 24 | run(`set(quux, true)`); 25 | // → Some kind of ReferenceError 26 | -------------------------------------------------------------------------------- /code/skillsharing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ejs-skillsharing", 3 | "version": "1.0.0", 4 | "main": "skillsharing_server.js", 5 | "description": "Skill-sharing website example from Eloquent JavaScript", 6 | "dependencies": { 7 | "serve-static": "^1.15.0" 8 | }, 9 | "license": "MIT", 10 | "bugs": "https://github.com/marijnh/Eloquent-JavaScript/issues", 11 | "homepage": "https://eloquentjavascript.net/21_skillsharing.html", 12 | "maintainers": [ 13 | { 14 | "name": "Marijn Haverbeke", 15 | "email": "marijn@haverbeke.berlin", 16 | "web": "https://marijnhaverbeke.nl/" 17 | } 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/marijnh/Eloquent-JavaScript.git" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/solutions/06_2_groups.js: -------------------------------------------------------------------------------- 1 | class Group { 2 | #members = []; 3 | 4 | add(value) { 5 | if (!this.has(value)) { 6 | this.#members.push(value); 7 | } 8 | } 9 | 10 | delete(value) { 11 | this.#members = this.#members.filter(v => v !== value); 12 | } 13 | 14 | has(value) { 15 | return this.#members.includes(value); 16 | } 17 | 18 | static from(collection) { 19 | let group = new Group; 20 | for (let value of collection) { 21 | group.add(value); 22 | } 23 | return group; 24 | } 25 | } 26 | 27 | let group = Group.from([10, 20]); 28 | console.log(group.has(10)); 29 | // → true 30 | console.log(group.has(30)); 31 | // → false 32 | group.add(10); 33 | group.delete(10); 34 | console.log(group.has(10)); 35 | // → false 36 | -------------------------------------------------------------------------------- /code/solutions/07_3_persistent_group.js: -------------------------------------------------------------------------------- 1 | class PGroup { 2 | #members; 3 | constructor(members) { 4 | this.#members = members; 5 | } 6 | 7 | add(value) { 8 | if (this.has(value)) return this; 9 | return new PGroup(this.#members.concat([value])); 10 | } 11 | 12 | delete(value) { 13 | if (!this.has(value)) return this; 14 | return new PGroup(this.#members.filter(m => m !== value)); 15 | } 16 | 17 | has(value) { 18 | return this.#members.includes(value); 19 | } 20 | 21 | static empty = new PGroup([]); 22 | } 23 | 24 | let a = PGroup.empty.add("a"); 25 | let ab = a.add("b"); 26 | let b = ab.delete("a"); 27 | 28 | console.log(b.has("b")); 29 | // → true 30 | console.log(a.has("b")); 31 | // → false 32 | console.log(b.has("a")); 33 | // → false 34 | -------------------------------------------------------------------------------- /code/solutions/07_1_measuring_a_robot.js: -------------------------------------------------------------------------------- 1 | function countSteps(state, robot, memory) { 2 | for (let steps = 0;; steps++) { 3 | if (state.parcels.length == 0) return steps; 4 | let action = robot(state, memory); 5 | state = state.move(action.direction); 6 | memory = action.memory; 7 | } 8 | } 9 | 10 | function compareRobots(robot1, memory1, robot2, memory2) { 11 | let total1 = 0, total2 = 0; 12 | for (let i = 0; i < 100; i++) { 13 | let state = VillageState.random(); 14 | total1 += countSteps(state, robot1, memory1); 15 | total2 += countSteps(state, robot2, memory2); 16 | } 17 | console.log(`Robot 1 needed ${total1 / 100} steps per task`) 18 | console.log(`Robot 2 needed ${total2 / 100}`) 19 | } 20 | 21 | compareRobots(routeRobot, [], goalOrientedRobot, []); 22 | -------------------------------------------------------------------------------- /code/solutions/15_1_balloon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |🎈
4 | 5 | 30 | -------------------------------------------------------------------------------- /code/solutions/08_2_the_locked_box.js: -------------------------------------------------------------------------------- 1 | const box = new class { 2 | locked = true; 3 | #content = []; 4 | 5 | unlock() { this.locked = false; } 6 | lock() { this.locked = true; } 7 | get content() { 8 | if (this.locked) throw new Error("Locked!"); 9 | return this.#content; 10 | } 11 | }; 12 | 13 | function withBoxUnlocked(body) { 14 | let locked = box.locked; 15 | if (locked) box.unlock(); 16 | try { 17 | return body(); 18 | } finally { 19 | if (locked) box.lock(); 20 | } 21 | } 22 | 23 | withBoxUnlocked(() => { 24 | box.content.push("gold piece"); 25 | }); 26 | 27 | try { 28 | withBoxUnlocked(() => { 29 | throw new Error("Pirates on the horizon! Abort!"); 30 | }); 31 | } catch (e) { 32 | console.log("Error raised:", e); 33 | } 34 | 35 | console.log(box.locked); 36 | // → true 37 | -------------------------------------------------------------------------------- /code/solutions/21_1_disk_persistence.mjs: -------------------------------------------------------------------------------- 1 | // This isn't a stand-alone file, only a redefinition of a few 2 | // fragments from skillsharing/skillsharing_server.js 3 | 4 | import {readFileSync, writeFile} from "node:fs"; 5 | 6 | const fileName = "./talks.json"; 7 | 8 | SkillShareServer.prototype.updated = function() { 9 | this.version++; 10 | let response = this.talkResponse(); 11 | this.waiting.forEach(resolve => resolve(response)); 12 | this.waiting = []; 13 | 14 | writeFile(fileName, JSON.stringify(this.talks), e => { 15 | if (e) throw e; 16 | }); 17 | }; 18 | 19 | function loadTalks() { 20 | try { 21 | return JSON.parse(readFileSync(fileName, "utf8")); 22 | } catch (e) { 23 | return {}; 24 | } 25 | } 26 | 27 | // The line that starts the server must be changed to 28 | new SkillShareServer(loadTalks()).start(8000); 29 | -------------------------------------------------------------------------------- /src/check_links.mjs: -------------------------------------------------------------------------------- 1 | import {readdirSync, readFileSync} from "fs" 2 | 3 | let files = Object.create(null) 4 | for (let name of readdirSync(".")) { 5 | let m = /^\d\d_(.*?)\.md$/.exec(name) 6 | if (m) files[m[1]] = readFileSync(name, "utf8") 7 | } 8 | files.fast = files.hints = "" 9 | 10 | let fail = 0 11 | function error(file, msg) { 12 | console.error(file + ": " + msg) 13 | fail = 1 14 | } 15 | 16 | let link = /\]\(([\w_]+)(?:#([\w_]+))?\)/g, m 17 | for (let file in files) { 18 | while (m = link.exec(files[file])) { 19 | let [_, file, anchor] = m 20 | let target = files[file] 21 | if (target == null) 22 | error(file, "Unknown target file: " + file) 23 | else if (anchor && target.indexOf("{{id " + anchor + "}}") == -1) 24 | error(file, "Non-existing anchor: " + file + "#" + anchor) 25 | } 26 | } 27 | 28 | process.exit(fail) 29 | -------------------------------------------------------------------------------- /code/solutions/15_2_mouse_trail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 33 | 34 | -------------------------------------------------------------------------------- /code/solutions/16_1_game_over.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
8 |
9 |
10 |
28 |
--------------------------------------------------------------------------------
/code/solutions/04_3_a_list.js:
--------------------------------------------------------------------------------
1 | function arrayToList(array) {
2 | let list = null;
3 | for (let i = array.length - 1; i >= 0; i--) {
4 | list = {value: array[i], rest: list};
5 | }
6 | return list;
7 | }
8 |
9 | function listToArray(list) {
10 | let array = [];
11 | for (let node = list; node; node = node.rest) {
12 | array.push(node.value);
13 | }
14 | return array;
15 | }
16 |
17 | function prepend(value, list) {
18 | return {value, rest: list};
19 | }
20 |
21 | function nth(list, n) {
22 | if (!list) return undefined;
23 | else if (n == 0) return list.value;
24 | else return nth(list.rest, n - 1);
25 | }
26 |
27 | console.log(arrayToList([10, 20]));
28 | // → {value: 10, rest: {value: 20, rest: null}}
29 | console.log(listToArray(arrayToList([10, 20, 30])));
30 | // → [10, 20, 30]
31 | console.log(prepend(10, prepend(20, null)));
32 | // → {value: 10, rest: {value: 20, rest: null}}
33 | console.log(nth(arrayToList([10, 20, 30]), 1));
34 | // → 20
35 |
--------------------------------------------------------------------------------
/code/solutions/14_2_elements_by_tag_name.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | A paragraph with one, two 5 | spans.
6 | 7 | 34 | -------------------------------------------------------------------------------- /code/solutions/07_2_robot_efficiency.js: -------------------------------------------------------------------------------- 1 | function lazyRobot({place, parcels}, route) { 2 | if (route.length == 0) { 3 | // Describe a route for every parcel 4 | let routes = parcels.map(parcel => { 5 | if (parcel.place != place) { 6 | return {route: findRoute(roadGraph, place, parcel.place), 7 | pickUp: true}; 8 | } else { 9 | return {route: findRoute(roadGraph, place, parcel.address), 10 | pickUp: false}; 11 | } 12 | }); 13 | 14 | // This determines the precedence a route gets when choosing. 15 | // Route length counts negatively, routes that pick up a package 16 | // get a small bonus. 17 | function score({route, pickUp}) { 18 | return (pickUp ? 0.5 : 0) - route.length; 19 | } 20 | route = routes.reduce((a, b) => score(a) > score(b) ? a : b).route; 21 | } 22 | 23 | return {direction: route[0], memory: route.slice(1)}; 24 | } 25 | 26 | runRobotAnimation(VillageState.random(), lazyRobot, []); 27 | -------------------------------------------------------------------------------- /src/client/editor.mjs: -------------------------------------------------------------------------------- 1 | import {EditorView, keymap, lineNumbers} from "@codemirror/view" 2 | import {EditorState, Compartment} from "@codemirror/state" 3 | import {minimalSetup} from "codemirror" 4 | import {html} from "@codemirror/lang-html" 5 | import {javascript} from "@codemirror/lang-javascript" 6 | import {bracketMatching, syntaxHighlighting} from "@codemirror/language" 7 | import {classHighlighter} from "@lezer/highlight" 8 | 9 | let modeCompartment = new Compartment 10 | 11 | export function createState(code, mode, extensions = []) { 12 | return EditorState.create({ 13 | doc: code, 14 | extensions: [ 15 | extensions, 16 | modeCompartment.of(mode == "html" ? html() : javascript()), 17 | minimalSetup, 18 | syntaxHighlighting(classHighlighter), 19 | bracketMatching(), 20 | lineNumbers(), 21 | EditorView.contentAttributes.of({"aria-label": "Code editor"}) 22 | ] 23 | }) 24 | } 25 | 26 | export function updateLanguage(mode) { 27 | return modeCompartment.reconfigure(mode == "html" ? html() : javascript()) 28 | } 29 | -------------------------------------------------------------------------------- /code/solutions/17_3_a_bouncing_ball.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 37 | -------------------------------------------------------------------------------- /code/solutions/11_3_building_promiseall.js: -------------------------------------------------------------------------------- 1 | function Promise_all(promises) { 2 | return new Promise((resolve, reject) => { 3 | let results = []; 4 | let pending = promises.length; 5 | for (let i = 0; i < promises.length; i++) { 6 | promises[i].then(result => { 7 | results[i] = result; 8 | pending--; 9 | if (pending == 0) resolve(results); 10 | }).catch(reject); 11 | } 12 | if (promises.length == 0) resolve(results); 13 | }); 14 | } 15 | 16 | // Test code. 17 | Promise_all([]).then(array => { 18 | console.log("This should be []:", array); 19 | }); 20 | function soon(val) { 21 | return new Promise(resolve => { 22 | setTimeout(() => resolve(val), Math.random() * 500); 23 | }); 24 | } 25 | Promise_all([soon(1), soon(2), soon(3)]).then(array => { 26 | console.log("This should be [1, 2, 3]:", array); 27 | }); 28 | Promise_all([soon(1), Promise.reject("X"), soon(3)]).then(array => { 29 | console.log("We should not get here"); 30 | }).catch(error => { 31 | if (error != "X") { 32 | console.log("Unexpected failure:", error); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /code/solutions/15_3_tabs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |(Note that this page is just an illustration. No actual message was delivered anywhere.)
15 | 16 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /code/solutions/19_3_circles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |Estos son los errores conocidos en la cuarta edición 20 | del libro. Para ver las erratas de otras ediciones, consulta estas páginas: primera, segunda, tercera. Para reportar un problema que no esté 24 | listado 25 | aquí, envíame un correo electrónico.
26 | 27 |Aún no se han encontrado problemas.
28 | 29 | 30 | 42 | 43 |Written by Marijn Haverbeke.
14 | 15 |Licensed under 16 | a Creative 17 | Commons attribution-noncommercial license. All code in this book 18 | may also be considered licensed under 19 | an MIT license.
20 | 21 |Illustrations by various artists: Cover 22 | by Péchane Sumi-e. Chapter illustrations by Madalina Tantareanu. 23 | Pixel art in Chapters 7 and 16 by Antonio Perdomo Pastor. Regular 24 | expression diagrams in Chapter 9 generated 25 | with regexper.com by Jeff 26 | Avallone. Village photograph in Chapter 11 by Fabrice Creuzot. 27 | Game concept for Chapter 16 28 | by Thomas Palef.
29 | 30 |A paper version of Eloquent JavaScript, including a bonus 31 | chapter, is being brought out 32 | by No Starch Press. They also 33 | sell a more polished EPUB version that includes the bonus 34 | chapter.
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /img/linked-list.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /code/solutions/14_1_build_a_table.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Puedes usar esta página para descargar el código fuente y soluciones a 27 | ejercicios para el libro Eloquent JavaScript, y para ejecutar código directamente 28 | en el contexto de los capítulos de ese libro, ya sea para resolver ejercicios o simplemente para experimentar.
29 | 30 |31 | Capítulo: 32 | 33 | 34 |
35 | 36 |Si has resuelto el ejercicio y quieres comparar tu código con 52 | el mío, o si realmente lo intentaste, pero no puedes hacer que tu código funcione, 53 | puedes (o descargarla).
55 | 56 |57 | El entorno base para este capítulo (si existe) está disponible en la 58 | caja de arena arriba, permitiéndote ejecutar los ejemplos del capítulo simplemente 59 | pegándolos en el editor. 60 |
61 |Este libro trata de JavaScript, programación y los maravillosos mundos digitales. Puedes leerlo online aquí, o 32 | comprar tu propia copia en papel (3ª edición y en inglés).
33 | 34 |Escrito por Marijn Haverbeke.
35 | 36 |Licenciado bajo 38 | una Licencia de Atribución-NoComercial de Creative 39 | Commons. Todo el código en este libro 40 | puede también considerarse licenciado bajo 41 | una licencia MIT. 42 |
43 | 44 |Ilustraciones de varios artistas: Portada 45 | por Péchane Sumi-e. Ilustraciones de capítulos por Madalina 46 | Tantareanu. Arte pixel en los Capítulos 7 y 16 por Antonio Perdomo 47 | Pastor. Diagramas de expresiones regulares en el Capítulo 9 generados 48 | con regexper.com por Jeff 49 | Avallone. Fotografía del pueblo en el Capítulo 11 por Fabrice Creuzot. Concepto de juego para el Capítulo 16 50 | por Thomas 51 | Palef.
52 |