A better way to learn JavaScript - Useful Snippets
$14.99
Minimum price
$29.99
Suggested price

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.

About the Author

Ajdin Imsirovic
Ajdin Imsirovic

Ajdin Imsirovic is a full-stack web developer who has published several courses (way back in 2015) on the subject of web design and web development. 

Before self-publishing books on Leanpub, he authored four books on front-end development for Packt Publishing:

  1. Bootstrap 4 Cookbook (Over 75 recipes to help you build elegant and responsive web applications with Bootstrap 4), June 2017
  2. Elm Web Development (An introductory guide to building funcational web apps using Elm), March 2018
  3. Vue.js Quick Start Guide (Learn how to build amazing and complex reactive web applications easily using Vue.js), October 2018
  4. Vue CLI 3 Quick Start Guide (Build and maintain Vue.js applications quickly with the standard CLI), May 2019

Bundles that include this book

$149.95
Suggested Price
$49.99
Bundle Price

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 or false
    • 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. Select three random elements from a web page
    • 16. Add random CSS classes to a paragraph
    • 17. Generate a random number between -10 and 10
    • 18. Generate a random sub-array from a larger array
    • 19. Never repeat a random dice throw twice in a row
    • 20. Get a palette of three shades of a random color
    • 21. 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
  • 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
  • Chapter 4: DOM manipulation
    • 1. Replace type="password" with type="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
  • 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
  • Chapter 8: Working with arrays
    • 1. Remove falsy values from an array
    • 2. Delete items from an array using filter() and map()
    • 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 to Array.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
  • 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 and JSON.stringify() on a JSON string
  • 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()
  • 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. Log out the response data using the fetch() method
  • 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
  • Chapter 14: Non-assorted exercises
    • 1. Show the difference between var, let, and const 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
  • 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 of this 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 to false prevent writable being set to false?
    • 30. Can we delete a property if its configurable is false?
    • 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 and super 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 using filter()
    • 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 of call() 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 to setTimeout()
    • 44. Use bind() to make invocation shortcut on Array.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 an Array
    • 61. Use a mapping function with Array.from()
    • 62. Convert a string to an Array with Array.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 to then()
    • 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

Authors have earned$10,270,421writing, publishing and selling on Leanpub, earning 80% royalties while saving up to 25 million pounds of CO2 and up to 46,000 trees.

Learn more about writing on Leanpub

The Leanpub 45-day 100% Happiness Guarantee

Within 45 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks.

See full terms

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), EPUB (for phones and tablets) and MOBI (for 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

Write and Publish on Leanpub

You can use Leanpub to easily write, publish and sell in-progress and completed ebooks and online courses! Leanpub is a powerful platform for serious authors, combining a simple, elegant writing and publishing workflow with a store focused on selling in-progress ebooks. Leanpub is a magical typewriter for authors: just write in plain text, and to publish your ebook, just click a button. It really is that easy.

Learn more about writing on Leanpub