├── LICENSE.md
├── Listing_1.1.html
├── Listing_1.2.html
├── Listing_1.3.js
├── Listing_1.4.txt
├── Listing_1.5.js
├── Listing_1.6.js
├── Listing_1.7.bash
├── Listing_10.1.js
├── Listing_10.2.js
├── Listing_10.3.js
├── Listing_10.4.js
├── Listing_10.5.js
├── Listing_10.6.js
├── Listing_10.7.js
├── Listing_10.8.js
├── Listing_10.9.js
├── Listing_11.1.js
├── Listing_11.10.js
├── Listing_11.2.html
├── Listing_11.3.html
├── Listing_11.4.js
├── Listing_11.5.js
├── Listing_11.6.js
├── Listing_11.7.js
├── Listing_11.8.js
├── Listing_11.9.html
├── Listing_2.1.js
├── Listing_2.10.js
├── Listing_2.11.js
├── Listing_2.12.js
├── Listing_2.13.js
├── Listing_2.14.js
├── Listing_2.15.js
├── Listing_2.16.js
├── Listing_2.17.js
├── Listing_2.18.js
├── Listing_2.2.js
├── Listing_2.3.js
├── Listing_2.4.js
├── Listing_2.5.html
├── Listing_2.6.js
├── Listing_2.7.js
├── Listing_2.8.js
├── Listing_2.9.js
├── Listing_3.1.js
├── Listing_3.2.js
├── Listing_3.3.js
├── Listing_3.4.js
├── Listing_3.5.js
├── Listing_4.1.html
├── Listing_4.2.js
├── Listing_4.3.js
├── Listing_4.4.js
├── Listing_4.5.js
├── Listing_4.6.js
├── Listing_5.1.js
├── Listing_5.10.js
├── Listing_5.11.js
├── Listing_5.12.js
├── Listing_5.13.js
├── Listing_5.14.txt
├── Listing_5.15.js
├── Listing_5.16.txt
├── Listing_5.17.js
├── Listing_5.18.js
├── Listing_5.19.js
├── Listing_5.2.html
├── Listing_5.3.js
├── Listing_5.4.html
├── Listing_5.5.html
├── Listing_5.6.js
├── Listing_5.7.html
├── Listing_5.8.js
├── Listing_5.9.js
├── Listing_6.1.js
├── Listing_6.2.js
├── Listing_6.3.js
├── Listing_6.4.js
├── Listing_6.5.js
├── Listing_6.6.js
├── Listing_6.7.js
├── Listing_6.8.js
├── Listing_6.9.js
├── Listing_7.1.js
├── Listing_7.10.js
├── Listing_7.11.js
├── Listing_7.12.js
├── Listing_7.13.js
├── Listing_7.2.js
├── Listing_7.3.js
├── Listing_7.4.js
├── Listing_7.5.js
├── Listing_7.6.js
├── Listing_7.7.js
├── Listing_7.8.js
├── Listing_7.9.js
├── Listing_8.1.txt
├── Listing_8.10.text
├── Listing_8.11.js
├── Listing_8.12.js
├── Listing_8.13.js
├── Listing_8.14.text
├── Listing_8.15.js
├── Listing_8.16.text
├── Listing_8.17.js
├── Listing_8.18.text
├── Listing_8.19.js
├── Listing_8.2.js
├── Listing_8.20.text
├── Listing_8.21.js
├── Listing_8.22.text
├── Listing_8.23.js
├── Listing_8.24.text
├── Listing_8.25.js
├── Listing_8.26.text
├── Listing_8.27.js
├── Listing_8.28.js
├── Listing_8.3.js
├── Listing_8.4.text
├── Listing_8.5.js
├── Listing_8.6.text
├── Listing_8.7.js
├── Listing_8.8.js
├── Listing_8.9.js
├── Listing_9.1.js
├── Listing_9.10.html
├── Listing_9.11.js
├── Listing_9.12.html
├── Listing_9.13.js
├── Listing_9.14.html
├── Listing_9.15.js
├── Listing_9.16.js
├── Listing_9.17.js
├── Listing_9.18.txt
├── Listing_9.2.txt
├── Listing_9.3.html
├── Listing_9.4.js
├── Listing_9.5.txt
├── Listing_9.6.html
├── Listing_9.7.js
├── Listing_9.8.js
├── Listing_9.9.js
└── README.md
/LICENSE.md:
--------------------------------------------------------------------------------
1 | ```
2 | The MIT License
3 |
4 | Copyright (c) 2022 Michael Hartl
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 | ```
24 |
--------------------------------------------------------------------------------
/Listing_1.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
7 |
8 | Hello, world!
9 | This page includes an alert written in JavaScript.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Listing_1.2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
9 |
10 |
11 | Hello, world!
12 | This page includes an alert written in JavaScript.
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Listing_1.3.js:
--------------------------------------------------------------------------------
1 | > console.log("hello, world!");
2 |
--------------------------------------------------------------------------------
/Listing_1.4.txt:
--------------------------------------------------------------------------------
1 | $ node
2 | >
3 |
--------------------------------------------------------------------------------
/Listing_1.5.js:
--------------------------------------------------------------------------------
1 | console.log("hello, world!");
2 |
--------------------------------------------------------------------------------
/Listing_1.6.js:
--------------------------------------------------------------------------------
1 | console.log("hello, world!", "how's it going?");
2 |
--------------------------------------------------------------------------------
/Listing_1.7.bash:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | console.log("hello, world!");
4 |
--------------------------------------------------------------------------------
/Listing_10.1.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | let fs = require("fs");
4 | let Phrase = require("-palindrome");
5 |
6 | let text = fs.readFileSync("phrases.txt", "utf-8");
7 | text.split("\n").forEach(function(line) {
8 | let phrase = new Phrase(line);
9 | if (phrase.palindrome()) {
10 | console.log("palindrome detected:", line);
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/Listing_10.2.js:
--------------------------------------------------------------------------------
1 | var urllib = require('urllib');
2 |
3 | urllib.request('http://cnodejs.org/', function (err, data, res) {
4 | if (err) {
5 | throw err; // you need to handle error
6 | }
7 | console.log(res.statusCode);
8 | console.log(res.headers);
9 | // data is Buffer instance
10 | console.log(data.toString());
11 | });
12 |
--------------------------------------------------------------------------------
/Listing_10.3.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | let urllib = require("urllib");
4 | let Phrase = require("mhartl-palindrome");
5 | let url = 'https://cdn.learnenough.com/phrases.txt'
6 |
7 | urllib.request(url, { followRedirect: true }, function(error, data, response) {
8 | let body = data.toString();
9 | body.split("\n").forEach(function(line) {
10 | let phrase = new Phrase(line);
11 | if (phrase.palindrome()) {
12 | console.log("palindrome detected:", line);
13 | }
14 | });
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/Listing_10.4.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | let urllib = require("urllib");
4 | let Phrase = require("-palindrome");
5 | let url = 'https://cdn.learnenough.com/phrases.txt'
6 |
7 | urllib.request(url, { followRedirect: true }, function(error, data, response) {
8 | let body = data.toString();
9 | let lines = body.split("\n");
10 | let palindromes = lines.filter(line => /* FILL IN */);
11 |
12 | palindromes.forEach(function(palindrome) {
13 | console.log("palindrome detected:", palindrome);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/Listing_10.5.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | // Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
4 |
5 | let urllib = require("urllib");
6 | let url = process.argv[2];
7 |
8 | console.log(url);
9 |
--------------------------------------------------------------------------------
/Listing_10.6.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | // Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
4 |
5 | let urllib = require("urllib");
6 | let url = process.argv[2];
7 |
8 | const jsdom = require("jsdom");
9 | const { JSDOM } = jsdom;
10 |
--------------------------------------------------------------------------------
/Listing_10.7.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | // Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
4 |
5 | let urllib = require("urllib");
6 | let url = process.argv[2];
7 |
8 | const jsdom = require("jsdom");
9 | const { JSDOM } = jsdom;
10 |
11 | urllib.request(url, { followRedirect: true }, function(error, data, response) {
12 | let body = data.toString();
13 | // Simulate a Document Object Model.
14 | let { document } = (new JSDOM(body)).window;
15 | });
16 |
--------------------------------------------------------------------------------
/Listing_10.8.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | // Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
4 |
5 | let urllib = require("urllib");
6 | let url = process.argv[2];
7 |
8 | const jsdom = require("jsdom");
9 | const { JSDOM } = jsdom;
10 |
11 | urllib.request(url, { followRedirect: true }, function(error, data, response) {
12 | let body = data.toString();
13 | // Simulate a Document Object Model.
14 | let { document } = (new JSDOM(body)).window;
15 |
16 | // Grab all the paragraphs and references.
17 | let paragraphs = document.querySelectorAll("p");
18 | let references = document.querySelectorAll(".reference");
19 | });
20 |
--------------------------------------------------------------------------------
/Listing_10.9.js:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/node
2 |
3 | // Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
4 |
5 | let urllib = require("urllib");
6 | let url = process.argv[2];
7 |
8 | const jsdom = require("jsdom");
9 | const { JSDOM } = jsdom;
10 |
11 | urllib.request(url, { followRedirect: true }, function(error, data, response) {
12 | let body = data.toString();
13 | // Simulate a Document Object Model.
14 | let { document } = (new JSDOM(body)).window;
15 |
16 | // Grab all the paragraphs and references.
17 | let paragraphs = document.querySelectorAll("p");
18 | let references = document.querySelectorAll(".reference");
19 |
20 | // Remove any references.
21 | references.forEach(function(reference) {
22 | reference.remove();
23 | });
24 |
25 | // Print out all of the paragraphs.
26 | paragraphs.forEach(function(paragraph) {
27 | console.log(paragraph.textContent);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/Listing_11.1.js:
--------------------------------------------------------------------------------
1 | function activateGallery() {
2 | alert("Hello from the gallery file!");
3 | }
4 |
--------------------------------------------------------------------------------
/Listing_11.10.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelectorAll("#gallery-thumbs > div > img");
6 | let mainImage = document.querySelector("#gallery-photo img");
7 |
8 | thumbnails.forEach(function(thumbnail) {
9 | // Preload large images.
10 | let newImageSrc = thumbnail.dataset.largeVersion;
11 | let largeVersion = new Image();
12 | largeVersion.src = FILL_IN;
13 |
14 | thumbnail.addEventListener("click", function() {
15 | // Set clicked image as display image.
16 | mainImage.setAttribute("src", newImageSrc);
17 |
18 | // Change which image is current.
19 | document.querySelector(".current").classList.remove("current");
20 | thumbnail.parentNode.classList.add("current");
21 |
22 | // Update image info.
23 | let galleryInfo = document.querySelector("#gallery-info");
24 | let title = galleryInfo.querySelector(".title");
25 | let description = galleryInfo.querySelector(".description");
26 |
27 | title.innerHTML = thumbnail.dataset.title;
28 | description.innerHTML = thumbnail.dataset.description;
29 | });
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/Listing_11.2.html:
--------------------------------------------------------------------------------
1 |
2 | .
3 | .
4 | .
5 |
6 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/Listing_11.3.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Gallery for Learn Enough JavaScript to Be Dangerous
4 | ---
5 |
6 |
7 |
8 |
9 |

13 |
14 | .
15 | .
16 | .
17 |
18 |

22 |
23 |
24 |
25 |
26 |

27 |
28 |
29 |
30 |
Pacific Sunset
31 |
A sunset over the Pacific Ocean.
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Listing_11.4.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelector("#gallery-thumbs").
6 | querySelectorAll("img");
7 | let mainImage = document.querySelector("#gallery-photo img");
8 |
9 | thumbnails.forEach(function(thumbnail) {
10 | thumbnail.addEventListener("click", function() {
11 | // Set clicked image as main image.
12 | let newImageSrc = thumbnail.dataset.largeVersion;
13 | mainImage.setAttribute("src", newImageSrc);
14 | });
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/Listing_11.5.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelector("#gallery-thumbs").
6 | querySelectorAll("img");
7 | let mainImage = document.querySelector("#gallery-photo img");
8 |
9 | thumbnails.forEach(function(thumbnail) {
10 | thumbnail.addEventListener("click", function() {
11 | // Set clicked image as main image.
12 | let newImageSrc = thumbnail.dataset.largeVersion;
13 | mainImage.setAttribute("src", newImageSrc);
14 | mainImage.setAttribute("alt", FILL_IN);
15 | });
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/Listing_11.6.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelectorAll("#gallery-thumbs > ??? > ???");
6 | let mainImage = document.querySelector("#gallery-photo img");
7 | .
8 | .
9 | .
10 | }
11 |
--------------------------------------------------------------------------------
/Listing_11.7.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelectorAll("#gallery-thumbs > div > img");
6 | let mainImage = document.querySelector("#gallery-photo img");
7 |
8 | thumbnails.forEach(function(thumbnail) {
9 | thumbnail.addEventListener("click", function() {
10 | // Set clicked image as display image.
11 | let newImageSrc = thumbnail.dataset.largeVersion;
12 | mainImage.setAttribute("src", newImageSrc);
13 |
14 | // Change which image is current.
15 | document.querySelector(".current").classList.remove("current");
16 | thumbnail.parentNode.classList.add("current");
17 | });
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/Listing_11.8.js:
--------------------------------------------------------------------------------
1 | // Activates the image gallery.
2 | // The main task is to attach an event listener to each image in the gallery
3 | // and respond appropriately on click.
4 | function activateGallery() {
5 | let thumbnails = document.querySelectorAll("#gallery-thumbs > div > img");
6 | let mainImage = document.querySelector("#gallery-photo img");
7 | // Image info to be updated
8 | let galleryInfo = document.querySelector("#gallery-info");
9 | let title = galleryInfo.querySelector(".title");
10 | let description = galleryInfo.querySelector(".description");
11 |
12 | thumbnails.forEach(function(thumbnail) {
13 | thumbnail.addEventListener("click", function() {
14 | // Set clicked image as display image.
15 | let newImageSrc = thumbnail.dataset.largeVersion;
16 | mainImage.setAttribute("src", newImageSrc);
17 |
18 | // Change which image is current.
19 | document.querySelector(".current").classList.remove("current");
20 | thumbnail.parentNode.classList.add("current");
21 |
22 | // Update image info.
23 | title.innerHTML = thumbnail.dataset.title;
24 | description.innerHTML = thumbnail.dataset.description;
25 | });
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/Listing_11.9.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Gallery for Learn Enough JavaScript to Be Dangerous
4 | ---
5 |
6 |
7 |
8 |
9 |

13 |
14 | .
15 | .
16 | .
17 |
18 |
19 |
20 |

21 |
22 |
23 |
24 |
Venice Beach
25 |
An overhead shot of Venice Beach, California.
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Listing_2.1.js:
--------------------------------------------------------------------------------
1 | > let firstName = "Michael";
2 | > let lastName = "Hartl";
3 |
--------------------------------------------------------------------------------
/Listing_2.10.js:
--------------------------------------------------------------------------------
1 | > true || true
2 | true
3 | > true || false
4 | true
5 | > false || true
6 | true
7 | > false || false
8 | false
9 |
--------------------------------------------------------------------------------
/Listing_2.11.js:
--------------------------------------------------------------------------------
1 | > if (x.length === 0 || y.length === 0) {
2 | "At least one of the strings is empty!";
3 | } else {
4 | "Neither of the strings is empty.";
5 | }
6 | 'At least one of the strings is empty!'
7 |
--------------------------------------------------------------------------------
/Listing_2.12.js:
--------------------------------------------------------------------------------
1 | > !true
2 | false
3 | > !false
4 | true
5 |
--------------------------------------------------------------------------------
/Listing_2.13.js:
--------------------------------------------------------------------------------
1 | > if (!(x.length === 0)) {
2 | "x is not empty.";
3 | } else {
4 | "x is empty.";
5 | }
6 | 'x is not empty.'
7 |
--------------------------------------------------------------------------------
/Listing_2.14.js:
--------------------------------------------------------------------------------
1 | > if (!x && !y) {
2 | "Both strings are empty!";
3 | } else {
4 | "At least one of the strings is nonempty.";
5 | }
6 | 'At least one of the strings is nonempty.'
7 |
--------------------------------------------------------------------------------
/Listing_2.15.js:
--------------------------------------------------------------------------------
1 | > let soliloquy = "To be, or not to be, that is the question:";
2 | > soliloquy.includes("To be"); // Does it include the substring "To be"?
3 | true
4 | > soliloquy.includes("question"); // What about "question"?
5 | true
6 | > soliloquy.includes("nonexistent"); // This string doesn't appear.
7 | false
8 | > soliloquy.includes("TO BE"); // String inclusion is case-sensitive.
9 | false
10 | > soliloquy.includes("To be", 1); // Can you guess what this one means?
11 | false
12 | > soliloquy.includes("o be,", 1); // A hint for the previous one
13 | true
14 |
--------------------------------------------------------------------------------
/Listing_2.16.js:
--------------------------------------------------------------------------------
1 | > console.log(soliloquy); // Just a reminder of what the string is
2 | To be, or not to be, that is the question:
3 | > soliloquy.charAt(0);
4 | 'T'
5 | > soliloquy.charAt(1);
6 | 'o'
7 | > soliloquy.charAt(2);
8 | ' '
9 |
--------------------------------------------------------------------------------
/Listing_2.17.js:
--------------------------------------------------------------------------------
1 | > for (let i = 0; i < 5; i++) {
2 | console.log(i);
3 | }
4 | 0
5 | 1
6 | 2
7 | 3
8 | 4
9 |
--------------------------------------------------------------------------------
/Listing_2.18.js:
--------------------------------------------------------------------------------
1 | > for (let i = 0; i < soliloquy.length; i++) {
2 | console.log(soliloquy.charAt(i));
3 | }
4 | T
5 | o
6 |
7 | b
8 | e
9 | .
10 | .
11 | .
12 | t
13 | i
14 | o
15 | n
16 | :
17 |
--------------------------------------------------------------------------------
/Listing_2.2.js:
--------------------------------------------------------------------------------
1 | > firstName + " " + lastName;
2 | 'Michael Hartl'
3 |
--------------------------------------------------------------------------------
/Listing_2.3.js:
--------------------------------------------------------------------------------
1 | var firstName = "Michael";
2 | var lastName = "Hartl";
3 |
--------------------------------------------------------------------------------
/Listing_2.4.js:
--------------------------------------------------------------------------------
1 | > firstName + " " + lastName; // Concatenation, with a space in between
2 | 'Michael Hartl'
3 | > `${firstName} ${lastName}`; // The equivalent interpolation
4 | 'Michael Hartl'
5 |
--------------------------------------------------------------------------------
/Listing_2.5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
10 |
11 |
12 | Hello, world!
13 | This page includes an alert written in JavaScript.
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Listing_2.6.js:
--------------------------------------------------------------------------------
1 | > let password = "foo";
2 | > if (password.length < 6) {
3 | "Password is too short.";
4 | }
5 | 'Password is too short.'
6 |
--------------------------------------------------------------------------------
/Listing_2.7.js:
--------------------------------------------------------------------------------
1 | > password = "foobar";
2 | > if (password.length < 6) {
3 | "Password is too short.";
4 | } else {
5 | "Password is long enough.";
6 | }
7 | 'Password is long enough.'
8 |
--------------------------------------------------------------------------------
/Listing_2.8.js:
--------------------------------------------------------------------------------
1 | > true && true
2 | true
3 | > false && true
4 | false
5 | > true && false
6 | false
7 | > false && false
8 | false
9 |
--------------------------------------------------------------------------------
/Listing_2.9.js:
--------------------------------------------------------------------------------
1 | > let x = "foo";
2 | > let y = "";
3 | > if (x.length === 0 && y.length === 0) {
4 | "Both strings are empty!";
5 | } else {
6 | "At least one of the strings is nonempty.";
7 | }
8 | 'At least one of the strings is nonempty.'
9 |
--------------------------------------------------------------------------------
/Listing_3.1.js:
--------------------------------------------------------------------------------
1 | > a[0];
2 | 'b'
3 | > a[1];
4 | 'a'
5 | > a[2];
6 | 'd'
7 |
--------------------------------------------------------------------------------
/Listing_3.2.js:
--------------------------------------------------------------------------------
1 | > a = ["ant", "bat", "cat", 42];
2 | [ 'ant', 'bat', 'cat', 42 ]
3 | > a.join(); // Join on default (comma).
4 | 'ant,bat,cat,42'
5 | > a.join(", "); // Join on comma-space.
6 | 'ant, bat, cat, 42'
7 | > a.join(" -- "); // Join on double dashes.
8 | 'ant -- bat -- cat -- 42'
9 | > a.join(""); // Join on empty space.
10 | 'antbatcat42'
11 |
--------------------------------------------------------------------------------
/Listing_3.3.js:
--------------------------------------------------------------------------------
1 | > for (let i = 0; i < soliloquy.length; i++) {
2 | console.log(soliloquy[i]);
3 | }
4 | T
5 | o
6 |
7 | b
8 | e
9 | .
10 | .
11 | .
12 | t
13 | i
14 | o
15 | n
16 | :
17 |
--------------------------------------------------------------------------------
/Listing_3.4.js:
--------------------------------------------------------------------------------
1 | > for (let i = 0; i < a.length; i++) {
2 | console.log(a[i]);
3 | }
4 | ant
5 | bat
6 | cat
7 | 42
8 |
--------------------------------------------------------------------------------
/Listing_3.5.js:
--------------------------------------------------------------------------------
1 | > let total = "";
2 | > for (let i = 0; i < a.length; i++) {
3 | // set total equal to the running total plus the current element
4 | }
5 |
--------------------------------------------------------------------------------
/Listing_4.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Listing_4.2.js:
--------------------------------------------------------------------------------
1 | > const sonnet = `Let me not to the marriage of true minds
2 | Admit impediments. Love is not love
3 | Which alters when it alteration finds,
4 | Or bends with the remover to remove.
5 | O no, it is an ever-fixed mark
6 | That looks on tempests and is never shaken;
7 | It is the star to every wand'ring bark,
8 | Whose worth's unknown, although his height be taken.
9 | Love's not time's fool, though rosy lips and cheeks
10 | Within his bending sickle's compass come:
11 | Love alters not with his brief hours and weeks,
12 | But bears it out even to the edge of doom.
13 | If this be error and upon me proved,
14 | I never writ, nor no man ever loved.`;
15 |
--------------------------------------------------------------------------------
/Listing_4.3.js:
--------------------------------------------------------------------------------
1 | > user;
2 | { firstName: 'Michael', lastName: 'Hartl' }
3 | > let otherUser = { firstName: 'Foo', lastName: 'Bar' };
4 | > otherUser["firstName"];
5 | 'Foo'
6 | > otherUser["lastName"];
7 | 'Bar'
8 |
--------------------------------------------------------------------------------
/Listing_4.4.js:
--------------------------------------------------------------------------------
1 | const sonnet = `Let me not to the marriage of true minds
2 | Admit impediments. Love is not love
3 | Which alters when it alteration finds,
4 | Or bends with the remover to remove.
5 | O no, it is an ever-fixed mark
6 | That looks on tempests and is never shaken;
7 | It is the star to every wand'ring bark,
8 | Whose worth's unknown, although his height be taken.
9 | Love's not time's fool, though rosy lips and cheeks
10 | Within his bending sickle's compass come:
11 | Love alters not with his brief hours and weeks,
12 | But bears it out even to the edge of doom.
13 | If this be error and upon me proved,
14 | I never writ, nor no man ever loved.`;
15 |
--------------------------------------------------------------------------------
/Listing_4.5.js:
--------------------------------------------------------------------------------
1 | const sonnet = `Let me not to the marriage of true minds
2 | Admit impediments. Love is not love
3 | Which alters when it alteration finds,
4 | Or bends with the remover to remove.
5 | O no, it is an ever-fixed mark
6 | That looks on tempests and is never shaken;
7 | It is the star to every wand'ring bark,
8 | Whose worth's unknown, although his height be taken.
9 | Love's not time's fool, though rosy lips and cheeks
10 | Within his bending sickle's compass come:
11 | Love alters not with his brief hours and weeks,
12 | But bears it out even to the edge of doom.
13 | If this be error and upon me proved,
14 | I never writ, nor no man ever loved.`;
15 |
16 | let uniques = {};
17 | let words = sonnet.match(/\w+/g);
18 |
--------------------------------------------------------------------------------
/Listing_4.6.js:
--------------------------------------------------------------------------------
1 | const sonnet = `Let me not to the marriage of true minds
2 | Admit impediments. Love is not love
3 | Which alters when it alteration finds,
4 | Or bends with the remover to remove.
5 | O no, it is an ever-fixed mark
6 | That looks on tempests and is never shaken;
7 | It is the star to every wand'ring bark,
8 | Whose worth's unknown, although his height be taken.
9 | Love's not time's fool, though rosy lips and cheeks
10 | Within his bending sickle's compass come:
11 | Love alters not with his brief hours and weeks,
12 | But bears it out even to the edge of doom.
13 | If this be error and upon me proved,
14 | I never writ, nor no man ever loved.`;
15 |
16 | // Unique words
17 | let uniques = {};
18 | // All words in the text
19 | let words = sonnet.match(/\w+/g);
20 |
21 | // Iterate through `words` and build up an associative array of unique words.
22 | for (let i = 0; i < words.length; i++) {
23 | let word = words[i];
24 | if (uniques[word]) {
25 | uniques[word] += 1;
26 | } else {
27 | uniques[word] = 1;
28 | }
29 | }
30 |
31 | console.log(uniques)
32 |
--------------------------------------------------------------------------------
/Listing_5.1.js:
--------------------------------------------------------------------------------
1 | > function numberCompare(a, b) {
2 | if (a > b) {
3 | return 1;
4 | } else if (a < b) {
5 | return -1;
6 | } else {
7 | return 0;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Listing_5.10.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return string.split("").reverse().join("");
4 | }
5 |
6 | // Returns true for a palindrome, false otherwise.
7 | function palindrome(string) {
8 | let processedContent = string.toLowerCase();
9 | return processedContent === reverse(processedContent);
10 | }
11 |
--------------------------------------------------------------------------------
/Listing_5.11.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("")
4 | }
5 |
6 | // Returns true for a palindrome, false otherwise.
7 | function palindrome(string) {
8 | let processedContent = string.toLowerCase();
9 | return processedContent === reverse(processedContent);
10 | }
11 |
--------------------------------------------------------------------------------
/Listing_5.12.js:
--------------------------------------------------------------------------------
1 | > function emailParts(email) {
2 | // FILL IN
3 | }
4 |
--------------------------------------------------------------------------------
/Listing_5.13.js:
--------------------------------------------------------------------------------
1 | let a = ["ant", "bat", "cat", 42];
2 | a.forEach(function(element) {
3 | console.log(element);
4 | });
5 |
--------------------------------------------------------------------------------
/Listing_5.14.txt:
--------------------------------------------------------------------------------
1 | $ node foreach.js
2 | ant
3 | cat
4 | bat
5 | 42
6 |
--------------------------------------------------------------------------------
/Listing_5.15.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | let soliloquy = "To be, or not to be, that is the question:";
5 | Array.from(soliloquy).forEach(function(character) {
6 | console.log(character);
7 | });
8 |
--------------------------------------------------------------------------------
/Listing_5.16.txt:
--------------------------------------------------------------------------------
1 | $ node foreach.js
2 | ant
3 | bat
4 | cat
5 | 42
6 | T
7 | o
8 |
9 | b
10 | e
11 | .
12 | .
13 | .
14 | t
15 | i
16 | o
17 | n
18 | :
19 |
--------------------------------------------------------------------------------
/Listing_5.17.js:
--------------------------------------------------------------------------------
1 | > let a = [8, 17, 42, 99];
2 | > a.sort(function(a, b) { return a - b; });
3 | [ 8, 17, 42, 99 ]
4 |
--------------------------------------------------------------------------------
/Listing_5.18.js:
--------------------------------------------------------------------------------
1 | % const sonnet = `Let me not to the marriage of true minds
2 | % .
3 | % .
4 | % .
5 | % But bears it out even to the edge of doom.
6 | % If this be error and upon me proved,
7 | % I never writ, nor no man ever loved.`;
8 |
9 | % // Unique words.
10 | % let uniques = {};
11 | % // All words in the text
12 | % let words = sonnet.match(/[\w']+/g);
13 |
14 | % // Iterate through `words` and build up a hash of unique words.
15 | % words.forEach(function(word) {
16 | % if (uniques[word]) {
17 | % uniques[word] += 1;
18 | % } else {
19 | % uniques[word] = 1;
20 | % }
21 | % });
22 |
23 | % console.log(uniques)
24 |
--------------------------------------------------------------------------------
/Listing_5.19.js:
--------------------------------------------------------------------------------
1 | % .
2 | % .
3 | % .
4 | % for (let word in uniques) {
5 | % console.log(`"${word}" appears ${uniques[word]} time(s)`);
6 | % }
7 |
--------------------------------------------------------------------------------
/Listing_5.2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Listing_5.3.js:
--------------------------------------------------------------------------------
1 | // Returns the day of the week for the given date.
2 | function dayName(date) {
3 | const daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday",
4 | "Thursday", "Friday", "Saturday"];
5 | return daysOfTheWeek[date.getDay()];
6 | }
7 |
--------------------------------------------------------------------------------
/Listing_5.4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Listing_5.5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Listing_5.6.js:
--------------------------------------------------------------------------------
1 | // Returns the day of the week for the given date.
2 | function dayName(date) {
3 | const daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday",
4 | "Thursday", "Friday", "Saturday"];
5 | return daysOfTheWeek[date.getDay()];
6 | }
7 |
8 | // Returns a greeting for the given date.
9 | function greeting(date) {
10 | // FILL IN
11 | }
12 |
--------------------------------------------------------------------------------
/Listing_5.7.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learn Enough JavaScript
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Listing_5.8.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return string.split("").reverse().join("");
4 | }
5 |
--------------------------------------------------------------------------------
/Listing_5.9.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return string.split("").reverse().join("");
4 | }
5 |
6 | // Returns true for a palindrome, false otherwise.
7 | function palindrome(string) {
8 | return string === reverse(string);
9 | }
10 |
--------------------------------------------------------------------------------
/Listing_6.1.js:
--------------------------------------------------------------------------------
1 | let states = ["Kansas", "Nebraska", "North Dakota", "South Dakota"];
2 |
3 | // urls: Imperative version
4 | function imperativeUrls(elements) {
5 | let urls = [];
6 | elements.forEach(function(element) {
7 | urls.push(element.toLowerCase().split(/\s+/).join("-"));
8 | });
9 | return urls;
10 | }
11 | console.log(imperativeUrls(states));
12 |
--------------------------------------------------------------------------------
/Listing_6.2.js:
--------------------------------------------------------------------------------
1 | let states = ["Kansas", "Nebraska", "North Dakota", "South Dakota"];
2 |
3 | // urls: Imperative version
4 | function imperativeUrls(elements) {
5 | let urls = [];
6 | elements.forEach(function(element) {
7 | urls.push(element.toLowerCase().split(/\s+/).join("-"));
8 | });
9 | return urls;
10 | }
11 | console.log(imperativeUrls(states));
12 |
13 | // urls: Functional version
14 | function functionalUrls(elements) {
15 | return elements.map(element => element.toLowerCase().split(/\s+/).join('-'));
16 | }
17 | console.log(functionalUrls(states));
18 |
--------------------------------------------------------------------------------
/Listing_6.3.js:
--------------------------------------------------------------------------------
1 | let states = ["Kansas", "Nebraska", "North Dakota", "South Dakota"];
2 |
3 | // Returns a URL-friendly version of a string.
4 | // Example: "North Dakota" -> "north-dakota"
5 | function urlify(string) {
6 | return string.toLowerCase().split(/\s+/).join("-");
7 | }
8 |
9 | // urls: Imperative version
10 | function imperativeUrls(elements) {
11 | let urls = [];
12 | elements.forEach(function(element) {
13 | urls.push(urlify(element));
14 | });
15 | return urls;
16 | }
17 | console.log(imperativeUrls(states));
18 |
19 | // urls: Functional version
20 | function functionalUrls(elements) {
21 | return elements.map(element => urlify(element));
22 | }
23 | console.log(functionalUrls(states));
24 |
--------------------------------------------------------------------------------
/Listing_6.4.js:
--------------------------------------------------------------------------------
1 | let states = ["Kansas", "Nebraska", "North Dakota", "South Dakota"];
2 | .
3 | .
4 | .
5 | // singles: Imperative version
6 | function imperativeSingles(elements) {
7 | let singles = [];
8 | elements.forEach(function(element) {
9 | if (element.split(/\s+/).length === 1) {
10 | singles.push(element);
11 | }
12 | });
13 | return singles;
14 | }
15 | console.log(imperativeSingles(states));
16 |
--------------------------------------------------------------------------------
/Listing_6.5.js:
--------------------------------------------------------------------------------
1 | let states = ["Kansas", "Nebraska", "North Dakota", "South Dakota"];
2 | .
3 | .
4 | .
5 | // singles: Imperative version
6 | function imperativeSingles(elements) {
7 | let singles = [];
8 | elements.forEach(function(element) {
9 | if (element.split(/\s+/).length === 1) {
10 | singles.push(element);
11 | }
12 | });
13 | return singles;
14 | }
15 | console.log(imperativeSingles(states));
16 |
17 | // singles: Functional version
18 | function functionalSingles(elements) {
19 | return elements.filter(element => element.split(/\s+/).length === 1);
20 | }
21 | console.log(functionalSingles(states));
22 |
--------------------------------------------------------------------------------
/Listing_6.6.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5 |
6 | // sum: Imperative solution
7 | function imperativeSum(elements) {
8 | let total = 0;
9 | elements.forEach(function(n) {
10 | total += n;
11 | });
12 | return total;
13 | }
14 | console.log(imperativeSum(numbers));
15 |
--------------------------------------------------------------------------------
/Listing_6.7.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5 |
6 | // sum: Imperative solution
7 | function imperativeSum(elements) {
8 | let total = 0;
9 | elements.forEach(function(n) {
10 | total += n;
11 | });
12 | return total;
13 | }
14 | console.log(imperativeSum(numbers));
15 |
16 | // sum: Functional solution
17 | function functionalSum(elements) {
18 | return elements.reduce((total, n) => { return total += n; });
19 | }
20 | console.log(functionalSum(numbers));
21 |
--------------------------------------------------------------------------------
/Listing_6.8.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | // lengths: Imperative solution
5 | function imperativeLengths(elements) {
6 | let lengths = {};
7 | elements.forEach(function(element) {
8 | lengths[element] = element.length;
9 | });
10 | return lengths;
11 | }
12 | console.log(imperativeLengths(states));
13 |
--------------------------------------------------------------------------------
/Listing_6.9.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | // lengths: Imperative solution
5 | function imperativeLengths(elements) {
6 | let lengths = {};
7 | elements.forEach(function(element) {
8 | lengths[element] = element.length;
9 | });
10 | return lengths;
11 | }
12 | console.log(imperativeLengths(states));
13 |
14 | // lengths: Functional solution
15 | function functionalLengths(elements) {
16 | return elements.reduce((lengths, element) => {
17 | lengths[element] = element.length;
18 | return lengths;
19 | }, {});
20 | }
21 | console.log(functionalLengths(states));
22 |
--------------------------------------------------------------------------------
/Listing_7.1.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | // Returns true for a palindrome, false otherwise.
7 | function palindrome(string) {
8 | let processedContent = string.toLowerCase();
9 | return processedContent === reverse(processedContent);
10 | }
11 |
12 | // Defines a Phrase object.
13 | function Phrase(content) {
14 | this.content = content;
15 | }
16 |
--------------------------------------------------------------------------------
/Listing_7.10.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | // Defines a Phrase object.
7 | function Phrase(content) {
8 | this.content = content;
9 |
10 | // Returns content processed for palindrome testing.
11 | this.processedContent = function processedContent() {
12 | return this.content.toLowerCase();
13 | }
14 |
15 | // Returns true if the phrase is a palindrome, false otherwise.
16 | this.palindrome = function palindrome() {
17 | return this.processedContent() === reverse(this.processedContent());
18 | }
19 | }
20 |
21 | // Defines a TranslatedPhrase object.
22 | function TranslatedPhrase(content, translation) {
23 | this.content = content;
24 | this.translation = translation;
25 |
26 | // Returns translation processed for palindrome testing.
27 | this.processedContent = function processedContent() {
28 | return this.translation.toLowerCase();
29 | }
30 | }
31 |
32 | TranslatedPhrase.prototype = new Phrase();
33 |
--------------------------------------------------------------------------------
/Listing_7.11.js:
--------------------------------------------------------------------------------
1 | > .load palindrome.js
2 | > frase = new TranslatedPhrase("recognize", "reconocer");
3 | > frase.palindrome();
4 | true
5 |
--------------------------------------------------------------------------------
/Listing_7.12.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | function Phrase(content) {
7 | this.content = content;
8 |
9 | this.processor = function(string) {
10 | // FILL IN
11 | }
12 |
13 | this.processedContent = function processedContent() {
14 | return this.processor(this.content);
15 | }
16 |
17 | // Returns true if the phrase is a palindrome, false otherwise.
18 | this.palindrome = function palindrome() {
19 | return this.processedContent() === reverse(this.processedContent());
20 | }
21 | }
22 |
23 | function TranslatedPhrase(content, translation) {
24 | this.content = content;
25 | this.translation = translation;
26 |
27 | // Returns translation processed for palindrome testing.
28 | this.processedContent = function processedContent() {
29 | return this.processor(this.translation);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Listing_7.13.js:
--------------------------------------------------------------------------------
1 | // Adds `reverse` to all strings.
2 | String.prototype.reverse = function() {
3 | return Array.from(this).reverse().join("");
4 | }
5 |
6 | // Defines a Phrase object.
7 | function Phrase(content) {
8 | this.content = content;
9 |
10 | // Returns content processed for palindrome testing.
11 | this.processedContent = function processedContent() {
12 | return this.content.toLowerCase();
13 | }
14 |
15 | // Returns true if the phrase is a palindrome, false otherwise.
16 | this.palindrome = function palindrome() {
17 | return this.processedContent() === this.processedContent().reverse();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Listing_7.2.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | // Defines a Phrase object.
7 | function Phrase(content) {
8 | this.content = content;
9 |
10 | // Returns true if the phrase is a palindrome, false otherwise.
11 | this.palindrome = function palindrome() {
12 | let processedContent = this.content.toLowerCase();
13 | return processedContent === reverse(processedContent);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Listing_7.3.js:
--------------------------------------------------------------------------------
1 | // Defines a Phrase object.
2 | function Phrase(content) {
3 | this.content = content;
4 |
5 | // Makes the phrase LOUDER.
6 | this.louder = function() {
7 | // FILL IN
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/Listing_7.4.js:
--------------------------------------------------------------------------------
1 | > .load palindrome.js
2 | > let p = new Phrase("yo adrian!");
3 | > p.louder();
4 | 'YO ADRIAN!'
5 |
--------------------------------------------------------------------------------
/Listing_7.5.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | // Defines a Phrase object.
7 | function Phrase(content) {
8 | this.content = content;
9 |
10 | this.palindrome = function palindrome() {
11 | let processedContent = this.content.toLowerCase();
12 | return processedContent === reverse(processedContent);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Listing_7.6.js:
--------------------------------------------------------------------------------
1 | // Reverses a string.
2 | function reverse(string) {
3 | return Array.from(string).reverse().join("");
4 | }
5 |
6 | // Defines a Phrase object.
7 | function Phrase(content) {
8 | this.content = content;
9 |
10 | // Returns content processed for palindrome testing.
11 | this.processedContent = function processedContent() {
12 | return this.content.toLowerCase();
13 | }
14 |
15 | // Returns true if the phrase is a palindrome, false otherwise.
16 | this.palindrome = function palindrome() {
17 | return this.processedContent() === reverse(this.processedContent());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Listing_7.7.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | // Defines a TranslatedPhrase object.
5 | function TranslatedPhrase(content, translation) {
6 | this.content = content;
7 | this.translation = translation;
8 | }
9 |
--------------------------------------------------------------------------------
/Listing_7.8.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | // Defines a TranslatedPhrase object.
5 | function TranslatedPhrase(content, translation) {
6 | this.content = content;
7 | this.translation = translation;
8 | }
9 |
10 | TranslatedPhrase.prototype = new Phrase();
11 |
--------------------------------------------------------------------------------
/Listing_7.9.js:
--------------------------------------------------------------------------------
1 | > .load palindrome.js
2 | > let frase = new TranslatedPhrase("recognize", "reconocer");
3 | > frase.palindrome();
4 | false
5 |
--------------------------------------------------------------------------------
/Listing_8.1.txt:
--------------------------------------------------------------------------------
1 | $ npm init
2 | package name: (mhartl-palindrome)
3 | version: (0.1.0)
4 | description: Palindrome detector
5 | entry point: (index.js)
6 | test command: mocha
7 | git repository: https://github.com/mhartl/mhartl-palindrome
8 | keywords: palindrome learn-enough javascript
9 | author: Michael Hartl
10 | license: (ISC)
11 | About to write to /Users/mhartl/repos/palindrome/package.json:
12 |
13 | {
14 | "name": "mhartl-palindrome",
15 | "version": "0.1.0",
16 | "description": "Palindrome detector",
17 | "main": "index.js",
18 | "scripts": {
19 | "test": "mocha"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/mhartl/mhartl-palindrome"
24 | },
25 | "author": "Michael Hartl",
26 | "license": "ISC"
27 | }
28 |
--------------------------------------------------------------------------------
/Listing_8.10.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | 1) should return true for a palindrome with punctuation
9 |
10 |
11 | 3 passing (8ms)
12 | 1 failing
13 |
14 | 1) Phrase
15 | #palindrome
16 | should return true for a palindrome with punctuation:
17 |
18 | AssertionError [ERR_ASSERTION]: false == true
19 | + expected - actual
20 |
21 | -false
22 | +true
23 |
--------------------------------------------------------------------------------
/Listing_8.11.js:
--------------------------------------------------------------------------------
1 | let punctuatedPalindrome = new Phrase("Madam, I'm Adam.");
2 | assert(punctuatedPalindrome.letters() === "MadamImAdam");
3 |
--------------------------------------------------------------------------------
/Listing_8.12.js:
--------------------------------------------------------------------------------
1 | assert.strictEqual(, );
2 |
--------------------------------------------------------------------------------
/Listing_8.13.js:
--------------------------------------------------------------------------------
1 | describe("Phrase", function() {
2 | .
3 | .
4 | .
5 | describe("#palindrome", function() {
6 | .
7 | .
8 | .
9 | });
10 |
11 | describe("#letters", function() {
12 | it("should return only letters", function() {
13 | let punctuatedPalindrome = new Phrase("Madam, I'm Adam.");
14 | assert.strictEqual(punctuatedPalindrome.letters(), "MadamImAdam");
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/Listing_8.14.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 | .
3 | .
4 | .
5 | 2) Phrase
6 | #letters
7 | should return only letters:
8 | TypeError: punctuatedPalindrome.letters is not a function
9 |
--------------------------------------------------------------------------------
/Listing_8.15.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 | .
3 | .
4 | .
5 | function Phrase(content) {
6 | .
7 | .
8 | .
9 | // Returns the letters in the content.
10 | this.letters = function letters() {
11 | return this.content; // stub return value
12 | }
13 |
14 | // Returns true if the phrase is a palindrome, false otherwise.
15 | this.palindrome = function palindrome() {
16 | return this.processedContent() === this.processedContent().reverse();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Listing_8.16.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | 1) should return true for a palindrome with punctuation
9 | #letters
10 | 2) should return only letters
11 |
12 |
13 | 3 passing (9ms)
14 | 2 failing
15 |
16 | 1) Phrase
17 | #palindrome
18 | should return true for a palindrome with punctuation:
19 |
20 | AssertionError [ERR_ASSERTION]: false == true
21 | + expected - actual
22 |
23 | -false
24 | +true
25 |
26 | at Context. (test/test.js:25:7)
27 |
28 | 2) Phrase
29 | #letters
30 | should return only letters:
31 |
32 | AssertionError [ERR_ASSERTION]: 'Madam, I\'m Adam.' === 'MadamImAdam'
33 | + expected - actual
34 |
35 | -Madam, I'm Adam.
36 | +MadamImAdam
37 |
--------------------------------------------------------------------------------
/Listing_8.17.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.content.toLowerCase();
15 | }
16 |
17 | // Returns the letters in the content.
18 | // For example:
19 | // new Phrase("Hello, world!").letters() === "Helloworld"
20 | this.letters = function letters() {
21 | let theLetters = [];
22 | for (let i = 0; i < this.content.length; i++) {
23 | if (this.content.charAt(i).match(/[a-zA-Z]/)) {
24 | theLetters.push(this.content.charAt(i));
25 | }
26 | }
27 | return theLetters.join("");
28 | }
29 |
30 | // Returns true if the phrase is a palindrome, false otherwise.
31 | this.palindrome = function palindrome() {
32 | return this.processedContent() === this.processedContent().reverse();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Listing_8.18.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | 1) should return true for a palindrome with punctuation
9 | #letters
10 | ✓ should return only letters
11 |
12 |
13 | 4 passing (8ms)
14 | 1 failing
15 |
16 | 1) Phrase
17 | #palindrome
18 | should return true for a palindrome with punctuation:
19 |
20 | AssertionError [ERR_ASSERTION]: false == true
21 | + expected - actual
22 |
23 | -false
24 | +true
25 |
--------------------------------------------------------------------------------
/Listing_8.19.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.letters().toLowerCase();
15 | }
16 |
17 | // Returns the letters in the content.
18 | // For example:
19 | // new Phrase("Hello, world!").letters() === "Helloworld"
20 | this.letters = function letters() {
21 | let theLetters = [];
22 | for (let i = 0; i < this.content.length; i++) {
23 | if (this.content.charAt(i).match(/[a-zA-Z]/)) {
24 | theLetters.push(this.content.charAt(i));
25 | }
26 | }
27 | return theLetters.join("");
28 | }
29 |
30 | // Returns true if the phrase is a palindrome, false otherwise.
31 | this.palindrome = function palindrome() {
32 | return this.processedContent() === this.processedContent().reverse();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Listing_8.2.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.content.toLowerCase();
15 | }
16 |
17 | // Returns true if the phrase is a palindrome, false otherwise.
18 | this.palindrome = function palindrome() {
19 | return this.processedContent() === this.processedContent().reverse();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Listing_8.20.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | ✓ should return true for a palindrome with punctuation
9 | #letters
10 | ✓ should return only letters
11 |
12 |
13 | 5 passing (6ms)
14 |
--------------------------------------------------------------------------------
/Listing_8.21.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.letters().toLowerCase();
15 | }
16 |
17 | // Returns the letters in the content.
18 | // For example:
19 | // new Phrase("Hello, world!").letters() === "Helloworld"
20 | this.letters = function letters() {
21 | let theLetters = [];
22 | const letterRegex = /[a-z]/i;
23 | Array.from(this.content).forEach(function(character) {
24 | if (character.match(letterRegex)) {
25 | theLetters.push(character);
26 | }
27 | });
28 | return theLetters.join("");
29 | }
30 |
31 | // Returns true if the phrase is a palindrome, false otherwise.
32 | this.palindrome = function palindrome() {
33 | return this.processedContent() === this.processedContent().reverse();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Listing_8.22.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | ✓ should return true for a palindrome with punctuation
9 | #letters
10 | ✓ should return only letters
11 |
12 |
13 | 5 passing (6ms)
14 |
--------------------------------------------------------------------------------
/Listing_8.23.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.letters().toLowerCase();
15 | }
16 |
17 | // Returns the letters in the content.
18 | // For example:
19 | // new Phrase("Hello, world!").letters() === "Helloworld"
20 | this.letters = function letters() {
21 | return Array.from(this.content).filter(c => c.match(/[a-z]/i)).join("");
22 | }
23 |
24 | // Returns true if the phrase is a palindrome, false otherwise.
25 | this.palindrome = function palindrome() {
26 | return this.processedContent() === this.processedContent().reverse();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Listing_8.24.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | ✓ should return true for a palindrome with punctuation
9 | #letters
10 | ✓ should return only letters
11 |
12 |
13 | 5 passing (6ms)
14 |
--------------------------------------------------------------------------------
/Listing_8.25.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.letters().toLowerCase();
15 | }
16 |
17 | // Returns the letters in the content.
18 | // For example:
19 | // new Phrase("Hello, world!").letters() === "Helloworld"
20 | this.letters = function letters() {
21 | return (this.content.match(/[a-z]/gi) || []).join("");
22 | }
23 |
24 | // Returns true if the phrase is a palindrome, false otherwise.
25 | this.palindrome = function palindrome() {
26 | return this.processedContent() === this.processedContent().reverse();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Listing_8.26.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | ✓ should return true for a mixed-case palindrome
8 | ✓ should return true for a palindrome with punctuation
9 | #letters
10 | ✓ should return only letters
11 |
12 |
13 | 5 passing (6ms)
14 |
--------------------------------------------------------------------------------
/Listing_8.27.js:
--------------------------------------------------------------------------------
1 | describe("Phrase", function() {
2 | .
3 | .
4 | .
5 | describe("#palindrome", function() {
6 | .
7 | .
8 | .
9 | });
10 |
11 | describe("#letters", function() {
12 | it("should return only letters", function() {
13 | let punctuatedPalindrome = new Phrase("Madam, I'm Adam.");
14 | assert.strictEqual(punctuatedPalindrome.letters(), "MadamImAdam");
15 | });
16 |
17 | it("should return the empty string on no match", function() {
18 | let noLetters = new Phrase("1234.56");
19 | assert.strictEqual(noLetters.letters(), "");
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/Listing_8.28.js:
--------------------------------------------------------------------------------
1 | this.letters = function letters() {
2 | const lettersRegEx = /[a-z]/gi;
3 | return // FILL IN
4 | }
5 |
--------------------------------------------------------------------------------
/Listing_8.3.js:
--------------------------------------------------------------------------------
1 | let assert = require("assert");
2 | let Phrase = require("../index.js");
3 |
4 | describe("Phrase", function() {
5 |
6 | describe("#palindrome", function() {
7 |
8 | it("should return false for a non-palindrome", function() {
9 | let nonPalindrome = new Phrase("apple");
10 | assert(!nonPalindrome.palindrome());
11 | });
12 |
13 | it("should return true for a plain palindrome", function() {
14 | let plainPalindrome = new Phrase("racecar");
15 | assert(plainPalindrome.palindrome());
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/Listing_8.4.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome()
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 |
8 | 2 passing (6ms)
9 |
--------------------------------------------------------------------------------
/Listing_8.5.js:
--------------------------------------------------------------------------------
1 | let assert = require("assert");
2 | let Phrase = require("../index.js");
3 |
4 | describe("Phrase", function() {
5 |
6 | describe("#palindrome", function() {
7 |
8 | it("should return false for a non-palindrome", function() {
9 | let nonPalindrome = new Phrase("apple");
10 | assert(!nonPalindrome.palindrome());
11 | });
12 |
13 | it("should return true for a plain palindrome", function() {
14 | let plainPalindrome = new Phrase("racecar");
15 | assert(plainPalindrome.palindrome());
16 | });
17 |
18 | it("should return true for a mixed-case palindrome");
19 |
20 | it("should return true for a palindrome with punctuation");
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/Listing_8.6.text:
--------------------------------------------------------------------------------
1 | $ npm test
2 |
3 | Phrase
4 | #palindrome
5 | ✓ should return false for a non-palindrome
6 | ✓ should return true for a plain palindrome
7 | - should return true for a mixed-case palindrome
8 | - should return true for a palindrome with punctuation
9 |
10 |
11 | 2 passing (6ms)
12 | 2 pending
13 |
--------------------------------------------------------------------------------
/Listing_8.7.js:
--------------------------------------------------------------------------------
1 | .
2 | .
3 | .
4 | it("should return true for a mixed-case palindrome", function() {
5 | let mixedCase = new Phrase("RaceCar");
6 | // Fill in this line
7 | });
8 | .
9 | .
10 | .
11 |
--------------------------------------------------------------------------------
/Listing_8.8.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | // Defines a Phrase object.
9 | function Phrase(content) {
10 | this.content = content;
11 |
12 | // Returns content processed for palindrome testing.
13 | this.processedContent = function processedContent() {
14 | return this.content;
15 | }
16 |
17 | // Returns true if the phrase is a palindrome, false otherwise.
18 | this.palindrome = function palindrome() {
19 | return this.processedContent() === this.processedContent().reverse();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Listing_8.9.js:
--------------------------------------------------------------------------------
1 | let assert = require("assert");
2 | let Phrase = require("../index.js");
3 |
4 | describe("Phrase", function() {
5 |
6 | describe("#palindrome", function() {
7 |
8 | it("should return false for a non-palindrome", function() {
9 | let nonPalindrome = new Phrase("apple");
10 | assert(!nonPalindrome.palindrome());
11 | });
12 |
13 | it("should return true for a plain palindrome", function() {
14 | let plainPalindrome = new Phrase("racecar");
15 | assert(plainPalindrome.palindrome());
16 | });
17 |
18 | it("should return true for a mixed-case palindrome", function() {
19 | let mixedCase = new Phrase("RaceCar");
20 | assert(mixedCase.palindrome());
21 | });
22 |
23 | it("should return true for a palindrome with punctuation", function() {
24 | let punctuatedPalindrome = new Phrase("Madam, I'm Adam.");
25 | assert(punctuatedPalindrome.palindrome());
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/Listing_9.1.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | alert(new Phrase("Madam, I'm Adam.").palindrome());
4 |
--------------------------------------------------------------------------------
/Listing_9.10.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Palindrome Tester
5 |
6 |
7 |
8 |
9 | Palindrome Tester
10 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Listing_9.11.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | function palindromeTester() {
4 | let string = prompt("Please enter a string for palindrome testing:");
5 | let phrase = new Phrase(string);
6 |
7 | if (phrase.palindrome()) {
8 | alert(`"${phrase.content}" is a palindrome!`);
9 | } else {
10 | alert(`"${phrase.content}" is not a palindrome.`)
11 | }
12 | }
13 |
14 | document.addEventListener("DOMContentLoaded", function() {
15 | let form = document.querySelector("#palindromeTester");
16 | form.addEventListener("submit", function() {
17 | palindromeTester();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/Listing_9.12.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Palindrome Tester
5 |
6 |
7 |
8 |
9 | Palindrome Tester
10 |
11 |
12 |
13 | Result
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Listing_9.13.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | function palindromeTester() {
4 | let string = prompt("Please enter a string for palindrome testing:");
5 | let phrase = new Phrase(string);
6 | let palindromeResult = document.querySelector("#palindromeResult");
7 |
8 | if (phrase.palindrome()) {
9 | palindromeResult.innerHTML = `"${phrase.content}" is a palindrome!`;
10 | } else {
11 | palindromeResult.innerHTML = `"${phrase.content}" is not a palindrome.`;
12 | }
13 | }
14 |
15 | document.addEventListener("DOMContentLoaded", function() {
16 | let button = document.querySelector("#palindromeTester");
17 | button.addEventListener("click", function() {
18 | palindromeTester();
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/Listing_9.14.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Palindrome Tester
5 |
6 |
7 |
8 |
9 | Palindrome Tester
10 |
11 |
16 |
17 | Result
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Listing_9.15.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | function palindromeTester(event) {
4 | event.preventDefault();
5 |
6 | let phrase = new Phrase(event.target.phrase.value);
7 | let palindromeResult = document.querySelector("#palindromeResult");
8 |
9 | if (phrase.palindrome()) {
10 | palindromeResult.innerHTML = `"${phrase.content}" is a palindrome!`;
11 | } else {
12 | palindromeResult.innerHTML = `"${phrase.content}" is not a palindrome.`;
13 | }
14 | }
15 |
16 | document.addEventListener("DOMContentLoaded", function() {
17 | let tester = document.querySelector("#palindromeTester");
18 | tester.addEventListener("submit", function(event) {
19 | palindromeTester(event);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/Listing_9.16.js:
--------------------------------------------------------------------------------
1 | let assert = require("assert");
2 | let Phrase = require("../index.js");
3 |
4 | describe("Phrase", function() {
5 |
6 | describe("#palindrome", function() {
7 | .
8 | .
9 | .
10 | it("should return false for an empty string", function() {
11 | let emptyPhrase = new Phrase("");
12 | assert(FILL_IN);
13 | });
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Listing_9.17.js:
--------------------------------------------------------------------------------
1 | module.exports = Phrase;
2 |
3 | // Adds `reverse` to all strings.
4 | String.prototype.reverse = function() {
5 | return Array.from(this).reverse().join("");
6 | }
7 |
8 | function Phrase(content) {
9 | this.content = content;
10 | .
11 | .
12 | .
13 | // Returns true if the phrase is a palindrome, false otherwise.
14 | this.palindrome = function palindrome() {
15 | if (this.processedContent()) {
16 | return this.processedContent() === this.processedContent().reverse();
17 | } else {
18 | return false;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Listing_9.18.txt:
--------------------------------------------------------------------------------
1 | $ npm update -palindrome
2 |
--------------------------------------------------------------------------------
/Listing_9.2.txt:
--------------------------------------------------------------------------------
1 | $ browserify main.js -o bundle.js
2 |
--------------------------------------------------------------------------------
/Listing_9.3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Palindrome Tester
5 |
6 |
7 |
8 |
9 | Palindrome Tester
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Listing_9.4.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | let string = prompt("Please enter a string for palindrome testing:");
4 | let phrase = new Phrase(string);
5 |
6 | if (phrase.palindrome()) {
7 | alert(`"${phrase.content}" is a palindrome!`);
8 | } else {
9 | alert(`"${phrase.content}" is not a palindrome.`)
10 | }
11 |
--------------------------------------------------------------------------------
/Listing_9.5.txt:
--------------------------------------------------------------------------------
1 | $ touch .nojekyll
2 | $ git add -A
3 | $ git commit -m "Prevent Jekyll build"
4 |
--------------------------------------------------------------------------------
/Listing_9.6.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Palindrome Tester
5 |
6 |
7 |
8 |
9 | Palindrome Tester
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Listing_9.7.js:
--------------------------------------------------------------------------------
1 | function palindromeTester() {
2 | let string = prompt("Please enter a string for palindrome testing:");
3 | let phrase = new Phrase(string);
4 |
5 | if (phrase.palindrome()) {
6 | alert(`"${phrase.content}" is a palindrome!`);
7 | } else {
8 | alert(`"${phrase.content}" is not a palindrome.`)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Listing_9.8.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | function palindromeTester() {
4 | let string = prompt("Please enter a string for palindrome testing:");
5 | let phrase = new Phrase(string);
6 |
7 | if (phrase.palindrome()) {
8 | alert(`"${phrase.content}" is a palindrome!`);
9 | } else {
10 | alert(`"${phrase.content}" is not a palindrome.`)
11 | }
12 | }
13 |
14 | let button = document.querySelector("#palindromeTester");
15 | button.addEventListener("click", function() {
16 | palindromeTester();
17 | });
18 |
--------------------------------------------------------------------------------
/Listing_9.9.js:
--------------------------------------------------------------------------------
1 | let Phrase = require("-palindrome");
2 |
3 | function palindromeTester() {
4 | let string = prompt("Please enter a string for palindrome testing:");
5 | let phrase = new Phrase(string);
6 |
7 | if (phrase.palindrome()) {
8 | alert(`"${phrase.content}" is a palindrome!`);
9 | } else {
10 | alert(`"${phrase.content}" is not a palindrome.`)
11 | }
12 | }
13 |
14 | document.addEventListener("DOMContentLoaded", function() {
15 | let button = document.querySelector("#palindromeTester");
16 | button.addEventListener("click", function() {
17 | palindromeTester();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learn Enough JavaScript Code Listings
2 |
3 | This repository contains files for all the code listings in *Learn Enough JavaScript to Be Dangerous* by Michael Hartl.
4 |
--------------------------------------------------------------------------------