A better way to learn JavaScript - Useful Snippets
A better way to learn JavaScript - Useful Snippets
Save Yet Another 1000 Hours Exploring JavaScript
About the Book
This book is the third in my 5-book series on JavaScript.
In Book 1 we learned about JS basics, and we got a nice foundation in the language.
In Book 2, we covered all the built-in objects in depth.
However, there is something lacking from both books: some more practical, simple examples, gotchas, tips and tricks.
This is what Book 3 is aiming at. We will go through various examples dealing with randomness, strings, numbers, DOM manipulation, and so on, all in the format of simple exercises, down-to-earth examples, with a lot of additional explanation so that the examples really make sense.
Currently, there are about 70 separate useful snippets. But this book is still in progress. By the time it's finished, there are going to be at least 300 snippets in this book.
If we take into account the first two books, by the time all three books are finished, we will be close to about 900 exercises to master your JavaScript knowledge.
My goal is to make a very comprehensive overview of the JavaScript language, spread over these 5 in-depth books, rich with examples and exercises.
Join me on this journey and grab your copy at this cheap price.
Bundles that include this book
Table of Contents
-
Chapter 0: Introduction
- Is this a book of algorithms?
- Describing an algorithm using a flow chart
- Conclusion
-
Chapter 1: Working with randomness
- 1. Emulate a six-sided dice
- 2. Pick a random member from an array
- 3. Emulate a six-sided dice (second approach)
- 4. Pick a random member from an array (second approach)
- Side-note: the anatomy of JS functions and a-ha moments
-
5. Randomly return a
true
orfalse
- 6. Get a number randomly from a range of numbers
- 7. Get a number randomly from a range of numbers (version 2)
- 8. Get a float randomly from a range of integers or floats
- 9. Generate a random string of characters
- 10. Generate a random hex color
- 11. Generate a random string of characters (second approach)
- 12. Generate a random Universally Unique Identifier
- 13. Randomize order of members in a JavaScript array (“shuffle”)
- 14. Generate a random password
- 15. Dice using the toString() and Array.pop()
- 16. Select three random elements from a web page
- 17. Add random CSS classes to a paragraph
- 18. Generate a random number between -10 and 10
- 19. Generate a random sub-array from a larger array
- 20. Never repeat a random dice throw twice in a row
- 21. Get a palette of three shades of a random color
-
22. Use
Math.random()
to imitate the bell curve
-
Chapter 2: Working with numbers
- 1. Format a number with a comma as thousands separator
- 2. Format a number as currency
- 3. Convert an array of numbers to an array of ordinal numbers
- 4. Count the number of times a sub-string appears in a string
- 5. Count all elements with background set to a specific color
- 6. Add leading zeros in front of a number
- 7. Add up (or subtract) all the arguments passed to a function
- 8. Multiply (or divide) all the arguments passed in to a function
- 9. Get the average value of all the arguments
- 10. Calculate a Fibonacci sequence
- 11. Compute the factorial of a number
- 12. Calculate the lazy caterer’s sequence
- 13. Convert a number into an array of its digits
- 14. Calculate the remainder of division of all arguments
- 15. Convert a string to a number
- 16. Round a number to a specific number of decimals
- 18. Skip the value (or limit the maximum value) with the modulus operator
- 19. Log out all the odd numbers in a given range
- 20. Log out all the even numbers in a given range
-
Chapter 3: Working with strings
- 1. Find all vowels in a piece of text
- 2. Convert a string to an array
- 3. Convert an array to a string
- 4. Capitalize a string
- 5. Capitalize the first letter of a string
- 6. Make the first character of a string lowercase
- 7. Capitalize the first letter of each word in a given string
- 8. Replace the first occurence of a substring with another string
- 9. Replace all instances of a substring with another string
- 10. Convert kebab case to camel case
- 11. Convert camel case to kebab case
- 12. Convert snake case to camel case
- 13. Convert a string to snake case
- 14. Convert a string to camel case
- 15. Convert a string to pascal case
- 16. Convert a string to kebab case
- 17. Repeat a string
- 18. Reverse a string
- 19. Check if a string is a palindrome
- 20. Find if a word is an anagram
- 21. Remove all whitespace from (multi-line) strings
- 22. Remove all new lines from a string
- 23. Strings are iterable, so let’s iterate to inspect them
- 24. Search chatgpt history of chat titles for a specific keyword
-
Chapter 4: DOM manipulation
-
1. Replace
type="password"
withtype="text"
-
2. Convert all inputs on a page into
type="text"
- 3. A simple recipe for styling anything on a page dynamically (using JS)
- 4. Check if one element is a parent of another element
- 5. Get the parent of an element
- 6. Get all siblings of an element
- 7. Check if an element is in focus (active)
- 8. Find all the attributes of a specific kind on a page
- 9. Insert a style tag with JavaScript
- 10. Get the dimensions of a given element in the DOM
- 11. Filter a JS object and show it in the DOM
- 12. Get the value of selected option
- 13. Wrap a div in another div dynamically
- 14. Apply a parent to an iframe
- 15. Remove an element by using its own reference
- 16. Query for elements with a specific text node
- 17. Trigger a mouseover event programatically
-
18. Inspect the document with
console.log
andconsole.dir
- 19. Count the number of specific element wrapped in another element
- 20. Find all elements on a page that do not have the position property set to static
- 21. Use the fluent DOM coding style
-
1. Replace
-
Chapter 5: Validating stuff
- 1. Validate that a given number is even
-
Chapter 6: Date and time exercises
- 1. Build a date that is N days from now
- 2. Display a live clock in the browser
-
Chapter 7: Working with functions and classes
- 1. Write a function that can be invoked multiple times at once
- 2. Write a function that can be invoked one time only
- 3. Check if a value is an async function
- 4. Check if a value is a generator function
- 5. Check if a value is any kind of function
- 6. Save all function calls in an array
- 7. Convert an async ES5 function into an async ES6 function
- 8. Make custom methods chainable
- 9. Write a debounce function
- 10. Use classes to replace functions in JS
- 11. Extend a class
- 12. Write a function that finds out how many stacks it takes to cause stack overflow
- 13. Write a function that takes any number and adds 10 to it
- 14. Write a function that calculates a specific exponent
- 15. Fun with functions, booleans, operators, and if-else statements
-
Chapter 8: Working with arrays
- 1. Remove falsy values from an array
-
2. Delete items from an array using
filter()
andmap()
- 3. Shallow copy an array
- 4. Partially hide characters in an email
- 5. Build a multi-dimensional array in JS
- 6. Flatten a two-dimensional array
-
7. Check if a specific value exists in array, using
filter()
- 8. Find the same values in two arrays
- 9. Build a sparse array
-
10. What happens when you pass a function to
Array.from()
? -
11. Pass an object with
length
property toArray.from()
to make a range of numbers - 12. Build a multiplication table with fizzBuzz checks built-in
- 13. Get the remaining array members after a specified position
- 14. Slice an array by N members, from beginning or end
-
15. Build an array of arrays with
map()
- 16. Rearrange an array by placing the last item to position 0
- 17. Revolve an array by N numbers
- 18. Filter an array into a sub-array with destructuring
- 19. How many pairs are there in a heap of gloves?
- 20. Add an item to the beginning of an array without using unshift
-
Chapter 9: Working with objects
- 1. Get the length of an object
- 2. Convert an object to array
-
3. Combine multiple objects into a new one using
Object.assign()
- 4. Build a new object as a subset of an existing object
-
Chapter 10: JSON and async-related exercises
-
1. Run
JSON.parse()
on an object andJSON.stringify()
on a JSON string
-
1. Run
-
Chapter 11: Loops
- 1. Give an example of setting and clearing an interval in JS, then use it as a “loop”
-
2. “Looping” with
requestAnimationFrame()
- 3. Use a for loop to output a string of any sequence of numbers
- 4. Use a for loop as a stand-in for an if statement
-
Chapter 12: XHR and AJAX
- 1. Display the steps that an XHR request goes through
- 2. Fetch data wrapped in a promise from an API and display it on a screen
-
3. Console log the response data using the
fetch()
method - 4. Optimize Asynchronous JavaScript: Sequential vs. Parallel Fetching with Promises
-
Chapter 13: Events
- 1. Find the key code for a keydown or keyup event
- 2. Find the amount of time that has passed between two button clicks
- 3. Improve events with closures
-
4. Prove that
event.target
is the same asthis
-
Chapter 14: Non-assorted exercises
-
1. Show the difference between
var
,let
, andconst
as related to hoisting - 2. Track the number of times a user clicked a button using localStorage
- 3. Make JavaScript talk
- 4. Encode and decode URI strings
- 5. Save, retrieve, and delete cookies with JavaScript
- 6. Swap two variables using an intermediary variable
- 7. Swap two variables using array destructuring
- 8. Swap two variables using basic math
-
9. Swap two variables using the XOR bitwise operator (
^
) - 10. Swap the values of n variables arbitrarily
-
11. Perform conditional logic without
if
,else
, orswitch
-
12. Using the
try catch
blocks with thesetTimeout()
method - 13. Removing unneccessary if-else conditional statements
-
1. Show the difference between
-
Appendix A: Snippets from Book 1
- Strings
- 1. Find the character at a specific position in a string
- 2. Find the index of a character in a string
- 3. Find the first and last occurence of a specific character in a string
- 4. Find the sort order of two strings
- 5. Split a string with a limit and a separator
- 6. Find capital leters in a string
- 7. Replace “dog eat dog” with “cat eat cat”
- 8. Find a word in a string with RegExp
- 9. Convert a JSON string to a JS object and vice versa
-
10. Explain polymorphism in JS with the
toString()
method - DOM Manipulation
- 1. Dynamically add a Bootstrap alert to a web page
- 2. Add contextual colors dynamically to a Bootstrap alert
- 3. Add Bootstrap to any page with JavaScript
- 4. Alert the user whenever they click on the body of a document
- 5. Add an event handler as a separate function
- 6. Change the color of a web page
- 7. Add an inline event handler to a div
- 8. Dynamically add an inline event handler to any web page
- 9. Capture and handle a mouseover event
- 10. Examine an event object
- 11. Add CSS classes using JavaScript
- Validation
- Date and time exercises
- 1. Save this moment in a variable
- 2. Save a previous moment in a variable
- 3. Convert a date to a string
- 4. Specify a date as a list of time unit arguments
- Functions
- 1. Generalize a function’s purpose
- 2. Generalize a function’s parameters
- 3. Show that you can call a function before defining it
- 4. Cause a stack overflow
- 5. Prove that a function expression is not hoisted
- 6. Give an example of a higher-order function
- 7. Return a closure from a higher-order function
- 8. Use default parameters in a function
-
9. Show that with
call()
we can specify the context ofthis
when invoking a function - 10. Avoid the strict mode throwing an error for a function definition inside an if statement
- 11. Show that an anonymous function’s name is an empty string
- 12. Prove that the variable assigned to an anonymous function becomes that function’s name
- 13. Passing objects to functions
-
14. What does calling
__proto__
return for a user-defined function? - Arrays
- 1. Find the max value in an array of numbers without using a loop
-
2. Replace an array member with
undefined
- 3. Check if a value exists in an array
- 4. Find the last member of array
-
5. Trim an array with
length
-
6. Trim an array with
pop()
-
7. Add to an array with
push()
-
8. Trim an array with
shift
-
9. Add to an array with
unshift
- 10. Extract the last two items from an array
-
11. Extract the first item with
splice()
- 12. Group multiple variables in an array
- 13. Get multiple variables out of an array
-
14. Trim an array using the
...
operator - 15. Concat two arrays
- 16. Convert an array to a string
- 17. Flip the order of items in an array
- 18. Sort an array of strings
- 19. Sort an array of numbers
-
20. Extract data from an array of objects using
Array.prototype.map
-
21. Sum up all array items with
Array.prototype.reduce
-
22. Add a fixed amount to any sum with
Array.prototype.reduce()
- 23. Find at least one member in array that passes some test
- 24. Check if all array items pass a test
-
25. “Find a thief” with
Array.prototype.find
- 26. Convert a set to an array
- 27. Convert an array to a set
- 28. Remove duplicates from an array using a set
- 29. Check if a value exists in a both a set and an array
- 30. Prove that arrays and sets hold to their members strongly
- 31. Prove that weak sets hold to their members weakly
- 32. Convert a map to an array
-
33. Define a computed getter on Array constructor’s
prototype
- Objects
- 1. Use object access operator (the dot) to expand a JS object
- 2. Expand an object using the bracket notation for the object property access
-
3. Show that static objects don’t use the keyword
new
- 4. Define a constructor function and build an object instance with it
-
5. Show that not using the
new
keyword with a constructor pollutes global scope -
6. Show that
window
is the global object in the browser -
7. Bind a specific
this
to an object and show that the bond won’t break - 8. Use computed properties in an object definition
- 9. Give an example of an async/await function
-
10. Show that we can’t use the built-in
arguments
variable in an arrow function - 11. Fix the above problem using the spread operator
-
12. Use
reduce()
in an arrow function to concat all args - 13. Convert a map to an object
- 14. Loop over an object with the help of maps
-
15. Show the difference between deleting a property and setting it to
undefined
on an object - 16. Show that with brackets notation, we can use variables to access object keys
- 17. Use a ternary to find the value of a property
- 18. Evaluate an expression inside an object with brackets notation
- 19. List out object’s properties
-
20. Build an object with a specific prototype using
Object.create()
- 21. Get an object’s own property descriptors
- 22. Make an object’s own property non-writable
- 23. Prove that setting a property as non-writable won’t work if that property is an object
- 24. Make nested objects read-only
- 25. Dynamically include/remove a property from being looped over in an object
- 26. Inspect all the object’s own enumerable property names
-
27. If
enumerable
is false, will it show in JSON.stringify on an object? -
28. Show in code what
configurable
does on an object’s property -
29. Does
configurable
set tofalse
preventwritable
being set tofalse
? -
30. Can we delete a property if its
configurable
isfalse
? - 31. Add a getter and a setter to an object
- 32. Give an example of a factory function
-
33. Make objects share methods using
Object.create()
- 34. Prove that in JavaScript, functions are objects
-
35. Show that
prototype
exists only on functions -
36. What does accessing
__proto__
on a user-defined object return? - 37. Why JavaScript is not class-based “under the hood”
- 38. Extend a constructor function’s prototype to keep functionality DRY
- 39. Fix the scoping issues of nested methods inside the user-extended properties on a constructor function’s prototype
-
40. Fix the
this
reference in inner functions -
41. Prove using code that the
toString()
method sits on an object literal’s prototype - 42. List three ways to check for an object’s prototype
-
43. Show what the
instanceof
does -
44. Chain constructors for an object with
call
- 45. Make constructors more versatile with a configuration object parameter
- 46. Give an example of a custom static method on a user-defined class
- 47. Make a property private on a user-defined class
-
48. Use
extends
andsuper
in a user-defined class - 49. Give an example of monkey-patching
- 50. By-pass inheritance using mixins
- 51. Show the difference between shallow copy and deep copy
- 52. Convert a JSON string to a JS object
- 53. Convert a JS object to a JSON string
- Loops
- 1. Run a block of code multiple times with a for loop
- 2. Run a for loop on an array of objects
- 3. Loop over an array with a condition
- 4. Cache the array length to speed up a for loop
-
5. Loop over an array of objects with
for..of
-
6. Show why you shouldn’t loop over an array with a
for..in
- 7. Loop over an array with the while loop
- 8. Loop over an array with the do while loop
-
9. Loop over an array with
forEach
-
10. Index the output of array items with
forEach
-
11. Loop over arrays with
Array.prototype.filter()
-
12. “Break out” of a
forEach
loop usingfilter()
- 13. Loop over JSON objects
- 14. Print JSON data to the screen using a forEach
- 15. Printing data to screen using nested for loops
- XHR and AJAX
-
1. Using the
setTimeout()
method, run some code after a specified amount of time - 2. Give an example of an XHR request
- 3. Give an example of a callback
- 4. Pass a function invocation to a function
- 5. Invoke a higher order function with two params, where the second param is a callback that takes the first param
- 6. Invoke a higher order function with two params, where the second param is a delayed callback
- 7. Run a callback function when a button is clicked
- 8. Run an asynchronous XHR inside a callback function
- 9. What’s the biggest difference between regular functions and asynchronous (callback) functions?
- 10. Why keep the result of a callback inside a callback?
- 11. Give an example of the pyramid of doom
-
12. Give an example of nested XHR calls with jQuery’s
getJSON()
method (including error handling) - 13. Mitigate callback hell by separating nested callbacks into named functions
-
14. Give an example of promises with
fetch()
- 15. Alert the data returned from a promise
- 16. Error handling in promises with catch() and finally()
-
17. Deal with rejected promises by passing the second argument to the
then()
method -
18. Use async/await with
fetch()
- 19. Invoke a function returned from a higher-order function, and use the returned function as an iterable
-
20. Implement the iteration protocol using
Symbol.iterator
- 21. Define a generator function
- 22. Show that an instance of the GeneratorFunction satisfies the iterator protocol
- 23. Show a suspended generator function and how yield works with it
-
24. Return values dynamically with
yield
- 25. Push the result of the third time a value gets yeilded, into an array
- 26. Combine generators with promises
- 27. Give an example of an async/await with fetch
- 28. Use an anonymous async function with an event
- 29. Subscribe to an observable data stream with RxJS
- Non-assorted exercises
- 1. Find the type of a primitive
- 2. Prove the immutability of primitives
- 3. Show that primitives are pass-by-value
- 4. Show that objects are pass-by-reference
-
5. Show the difference between the
==
and the===
operators - 6. Show that variables from inner scope can’t be used in outer scope
-
7. Prove that
let
doesn’t pollute global scope - 8. Find items that exist is both sets
- 9. Delete set members
- 10. Build and populate a map data structure
- 11. Pass multiple key-value pairs to a new map
- 12. Find the size of a map
- 13. Add key-value pairs to existing maps
- 14. Check if a key exists in a map
- 15. Deleting and clearing key-value pairs from maps
- 16. Build a WeakMap data structure
- 17. Loop over a Map data structure
-
18. What’s the convenience of
class
syntax in JS (with an example)? - 19. Throw an error in JS
- 20. Catch an error in JS
-
21. Show that
try
stops executing when error is thrown - 22. Throw an error with a custom message
-
23. Get a stack trace on demand with
console.trace
-
24. Show an example of debugging with
console.trace()
- 25. Show an example of stack tracing an error constructor
- 26. Perform some simple browser-sniffing
- 27. Show an example of feature-sniffing
-
28. Show how to use
console.assert()
-
29. Use
console.count
-
30. Use
console.time
- 31. Show the difference between unary prefix and postfix increment
- 32. Expose only parts of a module
-
Appendix B: Snippets from Book 2
- 1. Build a new object and specify its prototype
- 2. Copy enumerable own properties from one object to another
- 3. Copy enumerable own properties from multiple objects into a single object
- 4. Convert an array of arrays into an object
- 5. Covert an object into an array of arrays
- 6. Log out an object’s members as key-value pairs
- 7. Inspect an objects own property descriptor(s)
- 8. An alternative way of counting the number of members in an array
- 9. Count the number of members in an associative array
- 10. Find the number of own properties that an object has
- 11. Get values out of an associative array
- 12. On an object, add a named property with property descriptor editability
- 13. On an object, add multiple named properties with property descriptor editability
- 14. Prevent an object’s shallow properties from being deleted or changed (freeze an object)
- 15. Freeze an array
- 16. Prevent exensions of object’s properties but allow for deletions
- 17. Prevent extensions and deletions of an object’s properties
- 18. Define getters and setters on an object’s property
- 19. Define getters and setters directly on an object literal
- 20. Inspect getters and setters on an object’s specific property
- 21. Check if an object has an own property and return a boolean of the result
- 22. Check if an object’s own property’s property is enumerable
- 23. Check if an object is a prototype of another object
- 24. Call a method to check the number of arguments a function expects
-
25. Log out all the arguments passed to a function call using the
arguments
array-like object -
26. Apply an object as the
this
value of another object’s method -
27. Pass arguments to a function using the
apply()
method without specifying the this argument - 28. Concatenate any number of arguments using the built-in “arguments” array-like variable
- 29. Sum up any number of arguments using the built-in “arguments” array-like variable
-
30. Concatenate the values of all the object’s properties, using another object’s
joiner
function -
31. Borrow
Math.max()
static method and apply it on an array of numbers to get the highest number -
32. Borrow
Math.min()
static method and apply it on an array of numbers to get the highest number - 33. Use apply to monkey patch (extend) a built-in object as a polyfill on an older browser
-
34. Borrow a method from one object to another object using
call()
without arguments -
35. Borrow a method from one object to another object using
call()
with arguments -
36. Use
apply()
instead ofcall()
in a given code snippet -
37. Prove that every function call is calling the
call()
method in the background -
38. Chain constructors with the
call()
method -
39. Fix the problem of keeping the context of
this
in a nested function - 40. Why bind a function?
-
41. Use
bind()
to cement the context of this -
42. Use
bind()
to partially apply a function -
43. Use
bind()
to pass context tosetTimeout()
-
44. Use
bind()
to make invocation shortcut onArray.prototype.slice()
- 45. Set a symbol as an object’s key
- 46. Add a symbol to an object literal
- 47. Prove that each symbol is unique
-
48. Check if a variable is of type
symbol
- 49. Log out a symbol’s description
- 50. Why were symbols added to ES6?
- 51. Get the value of a symbol key from an object
-
52. Prove that symbols are excluded from
for..in
loops - 53. Add a symbol to an object without storing the symbol in a variable beforehand
- 54. Prove that symbols are skipped in JSON conversion
- 55. What will happen if we try to reassign an existing symbol property in an object
- 56. Use a symbol to fix an ENUM list
- 57. Show how to use a symbol as a metadata storage
-
58. Show a use case for the
Array[@@species]
accessor -
59. Reimplement a “regular” iterator with
Array.prototype[@@iterator]()
- 60. Build an iterator that iterates over every even member of an array
- 61. Build an iterator that iterates over every odd member of an array
-
60. Convert a
Set
to anArray
-
61. Use a mapping function with
Array.from()
-
62. Convert a
string
to anArray
withArray.of()
-
63. Iterate over an array with
Array.prototype.entries
-
64. Iterate over an array and break out of a loop based on a condition, using
Array.prototype.entries
-
65. Split an array into a series of arrays using
Array.prototype.entries
-
66. Split an array into a series of objects using
Array.prototype.entries
-
67. Push array keys into a separate array using
Array.prototype.keys
-
68. Print array values using
Array.prototype.values
-
69. Find index of a matching member of array or return -1 with
Array.prototype.findIndex
-
70. Search for a match from the end of array with
Array.prototype.lastIndexOf
-
71. Localize a decimal number as price with
Array.prototype.toLocaleString
-
72. Concatenate all args using
Array.prototype.reduce
-
73. Concatenate all args using
Array.prototype.reduceRight
- 74. How to throw errors in JS?
- 75. How to catch errors in JS gracefully?
- 76. How to customize error messages in JS?
-
77. Show that the
Promise()
constructor must take a callback function -
78. Why no error is thrown when we call
then()
on a promise, without passing any functions tothen()
- 79. Build a promise that randomly fetches data from coindesk or throws an error, and catches it
- 80. Display a message at the end of a promise regardless of whether it succeeds or fails
-
81. Deal with potential errors by passing the second argument to the
then()
call in a promise - 82. “Promisify” a method that does not usually return a promise object
- 83. Log out a sentence from inside a promise
- 84. Send a notification of a promise successfully fulfilled
-
85. Give an example of using
Promise.reject()
-
86. Give an example of using
Promise.resolve()
-
87. Return the
GeneratorFunction()
constructor -
88. Return the
AsyncFunction()
constructor -
89. Iterate values using
Generator.prototype.next()
-
90. Iterate an array using
Generator.prototype.next()
- 91. Send values to the generator
-
92. Show that the
Generator.prototype.return()
finishes the generator
Other books by this author
The Leanpub 60 Day 100% Happiness Guarantee
Within 60 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks.
Now, this is technically risky for us, since you'll have the book or course files either way. But we're so confident in our products and services, and in our authors and readers, that we're happy to offer a full money back guarantee for everything we sell.
You can only find out how good something is by trying it, and because of our 100% money back guarantee there's literally no risk to do so!
So, there's no reason not to click the Add to Cart button, is there?
See full terms...
Earn $8 on a $10 Purchase, and $16 on a $20 Purchase
We pay 80% royalties on purchases of $7.99 or more, and 80% royalties minus a 50 cent flat fee on purchases between $0.99 and $7.98. You earn $8 on a $10 sale, and $16 on a $20 sale. So, if we sell 5000 non-refunded copies of your book for $20, you'll earn $80,000.
(Yes, some authors have already earned much more than that on Leanpub.)
In fact, authors have earnedover $14 millionwriting, publishing and selling on Leanpub.
Learn more about writing on Leanpub
Free Updates. DRM Free.
If you buy a Leanpub book, you get free updates for as long as the author updates the book! Many authors use Leanpub to publish their books in-progress, while they are writing them. All readers get free updates, regardless of when they bought the book or how much they paid (including free).
Most Leanpub books are available in PDF (for computers) and EPUB (for phones, tablets and Kindle). The formats that a book includes are shown at the top right corner of this page.
Finally, Leanpub books don't have any DRM copy-protection nonsense, so you can easily read them on any supported device.
Learn more about Leanpub's ebook formats and where to read them