├── 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 | 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 | 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 |
12 | 13 |
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 |
12 | 13 |
14 | 15 |
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 | --------------------------------------------------------------------------------