├── Chapter 07 deepFreeze.js ├── Chapter 15 ├── index.html ├── src │ ├── CurrentUser.js │ ├── index.js │ ├── PureTodoStore.js │ ├── Store.js │ ├── TodoStore.js │ ├── decorators.js │ └── tools.js └── package.json ├── Chapter 07 ├── index.html ├── package.json └── src │ ├── Map.js │ └── List.js ├── Chapter 12 - Web Workers ├── src │ ├── index.js │ └── worker.js ├── index.html └── package.json ├── Chapter 14 ├── Stack.js ├── Queue.js ├── Counter.js ├── Service.js ├── Timer.js ├── Timer-prototypes.js └── EventEmitter.js ├── Chapter 09 Function Composition.js ├── Chapter 04 ├── Closures in loop 1 var.html ├── Closures in loop 2 let.html ├── Closures in loop 3 let.html └── Garbage Collection.html ├── Chapter 10.txt ├── Chapter 12.txt ├── Chapter 05 ├── debounce.html ├── throttle.html └── throttle and debounce.html ├── Chapter 16 ├── TodoStore-prototypes.js ├── TodoStore-Closures.js └── TodoStore-Java.txt ├── Chapter 08 Partial Application and Currying.js ├── readme.md ├── Chapter 05 Function Decorators.js ├── Chapter 13 ├── Memory Test - Prototypes.html └── Memory Test - Closures.html ├── Chapter 04.txt ├── Chapter 01.txt ├── Chapter 13.txt └── Chapter 02.txt /Chapter 07 deepFreeze.js: -------------------------------------------------------------------------------- 1 | function deepFreeze(object) { 2 | Object.keys(object).forEach(function freezeNestedObjects(name){ 3 | const value = object[name]; 4 | if(typeof value === "object") { 5 | deepFreeze(value); 6 | } 7 | }); 8 | return Object.freeze(object); 9 | } -------------------------------------------------------------------------------- /Chapter 15/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Method Decorators 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter 15/src/CurrentUser.js: -------------------------------------------------------------------------------- 1 | function CurrentUser() { 2 | function isAuthenticated() { 3 | return true; 4 | } 5 | 6 | return Object.freeze({ 7 | isAuthenticated 8 | }); 9 | } 10 | 11 | const currentUser = CurrentUser(); 12 | 13 | export default { ...currentUser }; 14 | -------------------------------------------------------------------------------- /Chapter 07/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Parcel Sandbox 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter 12 - Web Workers/src/index.js: -------------------------------------------------------------------------------- 1 | console.log("start application"); 2 | 3 | const worker = new Worker("/src/worker.js"); 4 | 5 | //send message to worker 6 | worker.postMessage("start"); 7 | 8 | //receive message from worker 9 | worker.onmessage = function(e) { 10 | console.log(e.data); 11 | worker.terminate(); 12 | }; 13 | -------------------------------------------------------------------------------- /Chapter 12 - Web Workers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Parcel Sandbox 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter 14/Stack.js: -------------------------------------------------------------------------------- 1 | function Stack(){ 2 | const list = []; 3 | 4 | function push(value){ 5 | list.push(value); 6 | } 7 | 8 | function pop(){ 9 | return list.pop(); 10 | } 11 | 12 | return Object.freeze({ 13 | push, 14 | pop 15 | }); 16 | } 17 | 18 | const stack = Stack(); 19 | stack.push(1); 20 | stack.push(2); 21 | stack.push(3); 22 | stack.pop(); //3 23 | stack.pop(); //2 -------------------------------------------------------------------------------- /Chapter 12 - Web Workers/src/worker.js: -------------------------------------------------------------------------------- 1 | function computeValue() { 2 | for (let i = 0; i < 10000000000; i++) {} 3 | return 10000000000; 4 | } 5 | 6 | //receive message from main thread 7 | onmessage = function(e) { 8 | const action = e.data; 9 | if (action === "start") { 10 | const result = computeValue(); 11 | 12 | //send message to main thread 13 | postMessage(result); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /Chapter 12 - Web Workers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webworkers", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 14/Queue.js: -------------------------------------------------------------------------------- 1 | function Queue(){ 2 | const list = []; 3 | 4 | function enqueue(value){ 5 | list.push(value); 6 | } 7 | 8 | function dequeue(){ 9 | return list.shift(); 10 | } 11 | 12 | return Object.freeze({ 13 | enqueue, 14 | dequeue 15 | }); 16 | } 17 | 18 | const queue = Queue(); 19 | queue.enqueue(1); 20 | queue.enqueue(2); 21 | queue.enqueue(3); 22 | queue.dequeue(); //1 23 | queue.dequeue(); //2 -------------------------------------------------------------------------------- /Chapter 09 Function Composition.js: -------------------------------------------------------------------------------- 1 | function compose(...functions){ 2 | return function(x){ 3 | return functions.reduceRight((value,f) => f(value), x); 4 | } 5 | } 6 | 7 | function f(y){ 8 | return y * y; 9 | } 10 | 11 | function g(x){ 12 | return x + x; 13 | } 14 | 15 | f(g(2)) === compose(f,g)(2); 16 | 17 | function pipe(...functions){ 18 | return function(x){ 19 | return functions.reduce((value, f) => f(value), x); 20 | } 21 | } -------------------------------------------------------------------------------- /Chapter 15/src/index.js: -------------------------------------------------------------------------------- 1 | import TodoStore from "./TodoStore"; 2 | import PureTodoStore from "./PureTodoStore"; 3 | 4 | const todoStore = TodoStore(); 5 | 6 | todoStore.add({ title: "todo1" }); 7 | todoStore.add({ title: "todo2" }); 8 | todoStore.add({ title: "todo3" }); 9 | 10 | const pureTodoStore = PureTodoStore(); 11 | pureTodoStore.add({ title: "todo1" }); 12 | pureTodoStore.add({ title: "todo2" }); 13 | pureTodoStore.add({ title: "todo3" }); 14 | -------------------------------------------------------------------------------- /Chapter 07/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "immutablejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": { 11 | "immutable": "4.0.0-rc.12" 12 | }, 13 | "devDependencies": { 14 | "@babel/core": "7.2.0", 15 | "parcel-bundler": "^1.6.1" 16 | }, 17 | "keywords": [] 18 | } 19 | -------------------------------------------------------------------------------- /Chapter 14/Counter.js: -------------------------------------------------------------------------------- 1 | function Counter(){ 2 | let state = 0; 3 | 4 | function increment(){ 5 | state += 1; 6 | return state; 7 | } 8 | 9 | function decrement(){ 10 | state -= 1; 11 | return state; 12 | } 13 | 14 | return Object.freeze({ 15 | increment, 16 | decrement 17 | }); 18 | }; 19 | 20 | const counter = Counter(); 21 | counter.increment();//1 22 | counter.increment();//2 23 | counter.increment();//3 24 | 25 | const otherCounter = Counter(); 26 | otherCounter.increment();//1 -------------------------------------------------------------------------------- /Chapter 04/Closures in loop 1 var.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter 04/Closures in loop 2 let.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter 15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "method-decorators", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": { 11 | "immutable": "4.0.0-rc.12", 12 | "lodash": "^4.17.11" 13 | }, 14 | "devDependencies": { 15 | "@babel/core": "7.2.0", 16 | "@types/lodash": "4.14.121", 17 | "parcel-bundler": "^1.6.1" 18 | }, 19 | "keywords": [] 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 04/Closures in loop 3 let.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /Chapter 15/src/PureTodoStore.js: -------------------------------------------------------------------------------- 1 | import Store from "./Store"; 2 | 3 | export function TodoStore() { 4 | let todos = []; 5 | 6 | function add(todos, todo) { 7 | return todos.concat([todo]); 8 | } 9 | 10 | function addAndMutate(todo) { 11 | todos = add(todos, todo); 12 | } 13 | 14 | return Object.freeze({ 15 | add: addAndMutate 16 | }); 17 | } 18 | 19 | function add(todos, todo) { 20 | return todos.concat([todo]); 21 | } 22 | 23 | export default Store({ 24 | state: [], 25 | setters: { add } 26 | }); 27 | -------------------------------------------------------------------------------- /Chapter 10.txt: -------------------------------------------------------------------------------- 1 | (() => { 2 | /*code*/ 3 | (() => { 4 | /*code*/ 5 | (() => { 6 | /*code*/ 7 | })(); 8 | })(); 9 | })(); 10 | 11 | 12 | (function createTodoModule(){ 13 | /*code*/ 14 | (function getAllTodos(){ 15 | /*code*/ 16 | (function renderTodo(){ 17 | /*code*/ 18 | })(); 19 | })(); 20 | })(); 21 | 22 | 23 | //with arrow function 24 | const prop = key => obj => obj[key]; 25 | 26 | //with function keyword 27 | function prop(key){ 28 | return function(obj){ 29 | return obj[key]; 30 | } 31 | } -------------------------------------------------------------------------------- /Chapter 12.txt: -------------------------------------------------------------------------------- 1 | function block(duration){ 2 | const starTime = Date.now(); 3 | while (Date.now() < starTime + duration) {} 4 | } 5 | 6 | function logMessage(){ 7 | console.log("process ended"); 8 | } 9 | 10 | block(5000); 11 | logMessage(); 12 | 13 | //----------------------------- 14 | 15 | function logMessage(){ 16 | console.log("process ended"); 17 | } 18 | 19 | function delay(duration, callback){ 20 | setTimeout(callback, duration); 21 | } 22 | 23 | delay(5000, logMessage); 24 | 25 | //----------------------------- 26 | 27 | for(let i=0; i<10000000000; i++){} 28 | 29 | 30 | -------------------------------------------------------------------------------- /Chapter 05/debounce.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter 05/throttle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter 15/src/Store.js: -------------------------------------------------------------------------------- 1 | import { decorateMethods } from "./tools"; 2 | 3 | function Store(storeConfig) { 4 | return function() { 5 | let state = storeConfig.state; 6 | 7 | function setter(fn) { 8 | return function(...args) { 9 | state = fn(state, ...args); 10 | }; 11 | } 12 | 13 | function getter(fn) { 14 | return function(...args) { 15 | return fn(state, ...args); 16 | }; 17 | } 18 | 19 | return Object.freeze({ 20 | ...decorateMethods(storeConfig.getters, getter), 21 | ...decorateMethods(storeConfig.setters, setter) 22 | }); 23 | }; 24 | } 25 | export default Store; 26 | -------------------------------------------------------------------------------- /Chapter 15/src/TodoStore.js: -------------------------------------------------------------------------------- 1 | import { compose, decorate } from "./tools"; 2 | import { logDuration, authorize } from "./decorators"; 3 | 4 | export function TodoStore_() { 5 | const todos = []; 6 | 7 | function add(todo) { 8 | todos.push(todo); 9 | } 10 | 11 | return Object.freeze({ 12 | add: compose( 13 | logDuration, 14 | authorize 15 | )(add) 16 | }); 17 | } 18 | 19 | function TodoStore() { 20 | let todos = []; 21 | 22 | function add(todo) { 23 | todos.push(todo); 24 | } 25 | 26 | return Object.freeze({ 27 | add 28 | }); 29 | } 30 | 31 | export default decorate(TodoStore, logDuration, authorize); 32 | -------------------------------------------------------------------------------- /Chapter 14/Service.js: -------------------------------------------------------------------------------- 1 | function Service() { 2 | function doSomething(){ 3 | console.log("do-something"); 4 | } 5 | 6 | return Object.freeze({ 7 | doSomething 8 | }); 9 | } 10 | 11 | function SpecialService({ service }){ 12 | function doSomethingElse(){ 13 | console.log("do-something-else"); 14 | } 15 | 16 | return Object.freeze({ 17 | doSomething : service.doSomething, 18 | doSomethingElse 19 | }); 20 | } 21 | 22 | const specialService = SpecialService({ 23 | service : Service() 24 | }); 25 | 26 | specialService.doSomething(); 27 | //"do-something" 28 | 29 | specialService.doSomethingElse(); 30 | //"do-something-else" -------------------------------------------------------------------------------- /Chapter 14/Timer.js: -------------------------------------------------------------------------------- 1 | function Timer(callback, interval){ 2 | let timerId; 3 | 4 | function executeAndStartTimer(){ 5 | callback().then(function makeNewCall(){ 6 | timerId = setTimeout(executeAndStartTimer, interval); 7 | }); 8 | } 9 | 10 | function stop(){ 11 | if(timerId){ 12 | clearTimeout(timerId); 13 | timerId = 0; 14 | } 15 | } 16 | 17 | function start(){ 18 | if(!timerId){ 19 | executeAndStartTimer(); 20 | } 21 | } 22 | 23 | return Object.freeze({ 24 | start, 25 | stop 26 | }); 27 | } 28 | 29 | function getTodos(){ 30 | return fetch("/todos"); 31 | } 32 | 33 | const timer = Timer(getTodos, 2000); 34 | timer.start(); -------------------------------------------------------------------------------- /Chapter 16/TodoStore-prototypes.js: -------------------------------------------------------------------------------- 1 | class TodoStore{ 2 | constructor(){ 3 | this.list = []; 4 | } 5 | 6 | push(todo){ 7 | this.list.push(todo); 8 | } 9 | 10 | getBy(text){ 11 | return this.list.filter(todo => todo.title.includes(text)); 12 | } 13 | } 14 | 15 | class Todo{ 16 | constructor(id, title){ 17 | this.id = id; 18 | this.title = title; 19 | } 20 | } 21 | 22 | (function startApplication(){ 23 | const todoStore = new TodoStore(); 24 | 25 | todoStore.push(new Todo(1, "find")); 26 | todoStore.push(new Todo(2, "read")); 27 | todoStore.push(new Todo(3, "share")); 28 | 29 | const filterTodos = todoStore.getBy("read"); 30 | console.log("Count:" + filterTodos.length); 31 | })(); -------------------------------------------------------------------------------- /Chapter 16/TodoStore-Closures.js: -------------------------------------------------------------------------------- 1 | function TodoStore(){ 2 | const list = []; 3 | 4 | function push(todo){ 5 | list.push(todo); 6 | } 7 | 8 | function getBy(text){ 9 | return list.filter(todo => todo.title.includes(text)); 10 | } 11 | 12 | return Object.freeze({ 13 | push, 14 | getBy 15 | }) 16 | } 17 | 18 | function Todo(id, title){ 19 | return Object.freeze({id, title}); 20 | } 21 | 22 | (function startApplication(){ 23 | const todoStore = TodoStore(); 24 | 25 | todoStore.push(Todo(1, "find")); 26 | todoStore.push(Todo(2, "read")); 27 | todoStore.push(Todo(3, "share")); 28 | 29 | const filterTodos = todoStore.getBy("read"); 30 | console.log("Count:" + filterTodos.length); 31 | })(); -------------------------------------------------------------------------------- /Chapter 15/src/decorators.js: -------------------------------------------------------------------------------- 1 | import currentUser from "./CurrentUser"; 2 | 3 | function logDuration(fn) { 4 | return function(...args) { 5 | const start = Date.now(); 6 | const result = fn(...args); 7 | const duration = Date.now() - start; 8 | console.log(fn.name + "() duration : " + duration); 9 | return result; 10 | }; 11 | } 12 | 13 | function createAuthorizeDecorator(currentUser) { 14 | return function authorize(fn) { 15 | return function(...args) { 16 | if (currentUser.isAuthenticated()) { 17 | return fn(...args); 18 | } else { 19 | throw new Error("Not authorized"); 20 | } 21 | }; 22 | }; 23 | } 24 | 25 | const authorize = createAuthorizeDecorator(currentUser); 26 | export { logDuration, authorize }; 27 | -------------------------------------------------------------------------------- /Chapter 15/src/tools.js: -------------------------------------------------------------------------------- 1 | export function compose(...functions) { 2 | return function(x) { 3 | return functions.reduceRight((value, f) => f(value), x); 4 | }; 5 | } 6 | 7 | function decorateMethods(obj, ...decorators) { 8 | const newObject = { ...obj }; 9 | Object.keys(newObject).forEach(function decorateMethod(fnName) { 10 | if (typeof newObject[fnName] === "function") { 11 | newObject[fnName] = compose(...decorators)(newObject[fnName]); 12 | } 13 | }); 14 | return newObject; 15 | } 16 | 17 | export function decorate(factory, ...decorators) { 18 | return function(...args) { 19 | const newObject = decorateMethods(factory(...args), ...decorators); 20 | return Object.freeze(newObject); 21 | }; 22 | } 23 | 24 | export { decorateMethods }; 25 | -------------------------------------------------------------------------------- /Chapter 04/Garbage Collection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 35 | 36 | -------------------------------------------------------------------------------- /Chapter 08 Partial Application and Currying.js: -------------------------------------------------------------------------------- 1 | function partial(fn, ...leftArgs) { 2 | return function(...rightArgs) { 3 | return fn(...leftArgs, ...rightArgs); 4 | } 5 | } 6 | 7 | function curry(f, length, leftArgs = []){ 8 | let noArguments = f.length; 9 | if(length) { 10 | noArguments = length; 11 | } 12 | 13 | return function(...args){ 14 | const allArgs = [...leftArgs, ...args]; 15 | if (allArgs.length >= noArguments){ 16 | return f(...allArgs); 17 | } else{ 18 | return curry(f, length, allArgs); 19 | } 20 | } 21 | } 22 | 23 | function thunk(fn, ...args){ 24 | return function(){ 25 | return fn(...args); 26 | } 27 | } 28 | 29 | function thunkify(fn) { 30 | return function(...args) { 31 | return function() { 32 | return fn(...args); 33 | }; 34 | }; 35 | } -------------------------------------------------------------------------------- /Chapter 14/Timer-prototypes.js: -------------------------------------------------------------------------------- 1 | class Timer { 2 | constructor(callback, interval){ 3 | this.callback = callback; 4 | this.interval = interval; 5 | this.timerId = 0; 6 | } 7 | 8 | executeAndStartTimer(){ 9 | this.callback().then(() => { 10 | this.timerId = setTimeout(this.executeAndStartTimer, this.interval); 11 | }); 12 | } 13 | 14 | start(){ 15 | if(this.timerId === 0){ 16 | this.executeAndStartTimer(); 17 | } 18 | } 19 | 20 | stop(){ 21 | if(this.timerId !== 0){ 22 | clearTimeout(this.timerId); 23 | this.timerId = 0; 24 | } 25 | } 26 | } 27 | 28 | function getTodos(){ 29 | return fetch("/todos"); 30 | } 31 | 32 | const timer = new Timer(getTodos,2000); 33 | 34 | timer.start = function() { 35 | console.log("don't start"); 36 | } 37 | timer.start(); //"don't start" -------------------------------------------------------------------------------- /Chapter 07/src/Map.js: -------------------------------------------------------------------------------- 1 | import { Map } from "immutable"; 2 | 3 | const book = Map({ 4 | title: "The Square and the Tower", 5 | author: "Niall Ferguson" 6 | }); 7 | 8 | //Add 9 | const description = "Networks and Hierarchies"; 10 | const bookWithDesc = book.set("description", description); 11 | console.log(bookWithDesc.toObject()); 12 | //{title:"The Square and the Tower",author:"Niall Ferguson",description:"Networks and Hierarchies"} 13 | 14 | //Edit 15 | const title = "Civilization"; 16 | const newBook = book.set("title", title); 17 | 18 | console.log(book.toObject()); 19 | //{title: "The Square and the Tower", author: "Niall Ferguson"} 20 | 21 | console.log(newBook.toObject()); 22 | //{title: "Civilization", author: "Niall Ferguson"} 23 | 24 | //Remove 25 | const newBook2 = book.remove("author"); 26 | console.log(newBook2.toObject()); 27 | //{title: "The Square and the Tower"} 28 | -------------------------------------------------------------------------------- /Chapter 07/src/List.js: -------------------------------------------------------------------------------- 1 | import { List } from "immutable"; 2 | 3 | const books = List([ 4 | { title: "JavaScript Allongé" }, 5 | { title: "You Don't Know JS" } 6 | ]); 7 | 8 | //Add 9 | const aNewBook = { title: "Mastering Immutable.js" }; 10 | const newBooks = books.push(aNewBook); 11 | 12 | console.log(Array.from(books)); 13 | //[{ title: "JavaScript Allongé" }, 14 | // { title: "You Don't Know JS" }] 15 | 16 | console.log(Array.from(newBooks)); 17 | //[{ title: "JavaScript Allongé" }, 18 | //{ title: "You Don't Know JS" }, 19 | //{ title: "Mastering Immutable.js" }] 20 | 21 | //Edit 22 | //const aNewBook = { title: "Mastering Immutable.js" }; 23 | const newBooks2 = books.set(0, aNewBook); 24 | console.log(Array.from(newBooks2)); 25 | //[{ title: "Mastering Immutable.js" }, 26 | // { title: "You Don't Know JS" }]; 27 | 28 | //Remove 29 | const newBooks3 = books.remove(0); 30 | console.log(Array.from(newBooks3)); 31 | //[{title: "You Don't Know JS"}]; 32 | -------------------------------------------------------------------------------- /Chapter 14/EventEmitter.js: -------------------------------------------------------------------------------- 1 | import partial from "lodash/partial"; 2 | 3 | function EventEmitter(){ 4 | const subscribers = []; 5 | 6 | function subscribe(type, callback){ 7 | subscribers[type] = subscribers[type] || []; 8 | subscribers[type].push(callback); 9 | } 10 | 11 | function notify(value, fn){ 12 | try { 13 | fn(value); 14 | } 15 | catch(e) { console.error(e); } 16 | } 17 | 18 | function publish(type, value){ 19 | if(subscribers[type]){ 20 | subscribers[type].forEach(partial(notify, value)); 21 | } 22 | } 23 | 24 | return Object.freeze({ 25 | subscribe, 26 | publish 27 | }); 28 | } 29 | 30 | const eventEmitter = EventEmitter(); 31 | 32 | eventEmitter.subscribe("update", doSomething); 33 | eventEmitter.subscribe("update", doSomethingElse); 34 | eventEmitter.subscribe("add", addItem); 35 | 36 | eventEmitter.publish("update", {}); 37 | 38 | function doSomething(value) { } 39 | function doSomethingElse(value) { } 40 | function addItem(value) { } -------------------------------------------------------------------------------- /Chapter 05/throttle and debounce.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | Fast click the buttons multiple times to fire many events. 10 |
11 | 43 | 44 | -------------------------------------------------------------------------------- /Chapter 16/TodoStore-Java.txt: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.ArrayList; 3 | import java.util.stream.Collectors; 4 | 5 | public class TodoStore 6 | { 7 | private List list; 8 | 9 | public TodoStore() 10 | { 11 | this.list = new ArrayList(); 12 | } 13 | 14 | public void push(Todo todo) 15 | { 16 | list.add(todo); 17 | } 18 | 19 | public List getBy(String text) 20 | { 21 | return list.stream() 22 | .filter(todo -> todo.Title.contains(text)) 23 | .collect(Collectors.toList()); 24 | } 25 | } 26 | 27 | public class Todo 28 | { 29 | public Integer Id; 30 | public String Title; 31 | 32 | public Todo(Integer id, String title) 33 | { 34 | this.Id = id; 35 | this.Title = title; 36 | } 37 | } 38 | 39 | public class StartApplication 40 | { 41 | public static void main(String[] args) 42 | { 43 | TodoStore todoStore = new TodoStore(); 44 | 45 | todoStore.push(new Todo(1, "find")); 46 | todoStore.push(new Todo(2, "read")); 47 | todoStore.push(new Todo(3, "share")); 48 | 49 | List filterTodos = todoStore.getBy("read"); 50 | System.out.print("Count:" + filterTodos.size()); 51 | } 52 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### Discover Functional JavaScript 2 | #### Source Code 3 | 4 | JavaScript brings functional programming to the mainstream and offers a new way of doing object-oriented programming without classes and prototypes. 5 | 6 | Programming in a functional style means using concepts such as first-class functions, closures, higher-order functions, partial application, currying, immutability, or pure functions. 7 | 8 | Functional programming promises to make code easier to read, understand, test, debug, or compose. Can we build an application using only pure functions? 9 | 10 | Decorators are a tool for reusing common logic and creating variations of existing functions. 11 | 12 | Closure can encapsulate state. Multiple closures sharing the same private state can create flexible and encapsulated objects. 13 | 14 | "One of the best new Functional Programming ebooks" - BookAuthority 15 | 16 | [https://www.amazon.com/dp/B07PBQJYYG](https://www.amazon.com/dp/B07PBQJYYG) 17 | 18 | [https://www.amazon.co.uk/dp/B07PBQJYYG](https://www.amazon.co.uk/dp/B07PBQJYYG) 19 | 20 | [https://www.amazon.es/dp/B07PBQJYYG](https://www.amazon.es/dp/B07PBQJYYG) 21 | 22 | [https://www.amazon.fr/dp/B07PBQJYYG](https://www.amazon.fr/dp/B07PBQJYYG) 23 | -------------------------------------------------------------------------------- /Chapter 05 Function Decorators.js: -------------------------------------------------------------------------------- 1 | function once(fn){ 2 | let returnValue; 3 | let canRun = true; 4 | return function(...args){ 5 | if(canRun) { 6 | returnValue = fn(...args); 7 | canRun = false; 8 | } 9 | return returnValue; 10 | } 11 | } 12 | 13 | function after(fn, startCount){ 14 | let count = 0; 15 | return function(...args){ 16 | count = count + 1; 17 | if (count >= startCount) { 18 | return fn(...args); 19 | } 20 | } 21 | } 22 | 23 | function throttle(fn, interval) { 24 | let lastTime; 25 | return function throttled(...args) { 26 | if(!lastTime || (Date.now() - lastTime >= interval)) { 27 | fn(...args); 28 | lastTime = Date.now(); 29 | } 30 | } 31 | } 32 | 33 | function debounce(fn, interval) { 34 | let timer; 35 | return function debounced(...args) { 36 | clearTimeout(timer); 37 | timer = setTimeout(function(){ 38 | fn(...args); 39 | }, interval); 40 | } 41 | } 42 | 43 | function memoize(fn) { 44 | const map = Object.create(null); 45 | return function (x) { 46 | if (!map[x]){ 47 | map[x] = fn(x); 48 | } 49 | 50 | return map[x]; 51 | } 52 | } 53 | 54 | function unary(fn){ 55 | return function(first){ 56 | return fn(first); 57 | } 58 | } 59 | 60 | function binary(fn){ 61 | return function(a, b){ 62 | return fn(a, b); 63 | } 64 | } -------------------------------------------------------------------------------- /Chapter 13/Memory Test - Prototypes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Chapter 13/Memory Test - Closures.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Chapter 04.txt: -------------------------------------------------------------------------------- 1 | (function autorun(){ 2 | let x = 1; 3 | function log(){ 4 | console.log(x); 5 | } 6 | log(); 7 | })(); 8 | 9 | 10 | (function autorun(){ 11 | let x = 1; 12 | function log(){ 13 | console.log(x); 14 | }; 15 | 16 | function run(fn){ 17 | let x = 100; 18 | fn(); 19 | } 20 | 21 | run(log); //1 22 | })(); 23 | 24 | 25 | (function autorun(){ 26 | let x = 1; 27 | setTimeout(function log(){ 28 | console.log(x); 29 | }, 10000); 30 | })(); 31 | 32 | 33 | (function autorun(){ 34 | let x = 1; 35 | $("#btn").click(function log(){ 36 | console.log(x); 37 | }); 38 | })(); 39 | 40 | 41 | (function autorun(){ 42 | let x = 1; 43 | fetch("/todos").then(function log(){ 44 | console.log(x); 45 | }); 46 | })(); 47 | 48 | //-------------------- 49 | 50 | function* sequence(){ 51 | let count = 0; 52 | while(true) { 53 | count += 1; 54 | yield count; 55 | } 56 | } 57 | 58 | const generator = sequence(); 59 | generator.next().value; //1 60 | generator.next().value; //2 61 | generator.next().value; //3 62 | 63 | //-------------------- 64 | 65 | function sequence(){ 66 | let count = 0; 67 | return function(){ 68 | count += 1; 69 | return count; 70 | } 71 | } 72 | 73 | const generator = sequence(); 74 | generator(); //1 75 | generator(); //2 76 | generator(); //3 77 | 78 | //-------------------- 79 | 80 | const counter = (function(){ 81 | let state = 0; 82 | 83 | function increment(){ 84 | state += 1; 85 | return state; 86 | } 87 | 88 | function decrement(){ 89 | state -= 1; 90 | return state; 91 | } 92 | 93 | return { 94 | increment, 95 | decrement 96 | } 97 | })(); 98 | 99 | counter.increment(); //1 100 | counter.increment(); //2 101 | counter.decrement(); //1 102 | 103 | //-------------------- 104 | 105 | //module "./counter.js" 106 | let state = 0; 107 | 108 | function increment() { 109 | state += 1; 110 | return state; 111 | } 112 | 113 | function decrement() { 114 | state -= 1; 115 | return state; 116 | } 117 | 118 | export default { 119 | increment, 120 | decrement 121 | } 122 | 123 | //module "./index.js" 124 | import counter from "./counter"; 125 | 126 | counter.increment(); //1 127 | counter.increment(); //2 128 | counter.decrement(); //1 129 | 130 | -------------------------------------------------------------------------------- /Chapter 01.txt: -------------------------------------------------------------------------------- 1 | (123).toString(); //"123" 2 | (1.23).toFixed(1); //"1.2" 3 | 4 | 5 | Number.parseInt("1"); //1 6 | Number.parseInt("text"); //NaN 7 | Number.parseFloat("1.234"); //1.234 8 | Number("1"); //1 9 | Number("1.234"); //1.234 10 | 11 | 12 | "text".substring(1,3); //"ex" 13 | "text".indexOf('x'); //2 14 | "text".concat(" end"); //"text end" 15 | 16 | 17 | if('') { 18 | console.log("true"); 19 | } else { 20 | console.log("false"); 21 | } 22 | 23 | 24 | let obj = { 25 | message: "read me", 26 | doSomething: function() {} 27 | } 28 | 29 | 30 | let obj = {}; 31 | obj.message = "read me"; //add 32 | obj.message = "enjoy"; //edit 33 | delete obj.message; //remove 34 | 35 | 36 | let stack = []; 37 | stack.push(1); //[1] 38 | stack.push(2); //[1, 2] 39 | let last = stack.pop(); //[1] 40 | console.log(last); //2 41 | 42 | 43 | let queue = []; 44 | queue.push(1); //[1] 45 | queue.push(2); //[1, 2] 46 | let first = queue.shift();//[2] 47 | console.log(first); //1 48 | 49 | 50 | (function autorun(){ 51 | console.log("executed"); 52 | })(); 53 | //"executed" 54 | 55 | 56 | let theObject = { 57 | name: "name", 58 | getName: function(){ 59 | return this.name; 60 | } 61 | } 62 | 63 | theObject.getName(); //"name" 64 | 65 | //---------------- 66 | 67 | let otherObject = { 68 | name: "otherName" 69 | } 70 | 71 | function getName(){ 72 | return this.name; 73 | } 74 | 75 | getName.apply(otherObject); //"otherName" 76 | getName.call(otherObject); //"otherName" 77 | 78 | //---------------- 79 | 80 | "use strict"; 81 | function getName(){ 82 | return this.name; 83 | } 84 | 85 | getName(); 86 | //Cannot read property 'name' of undefined 87 | 88 | //---------------- 89 | 90 | function logAll(){ 91 | console.log(arguments); 92 | } 93 | 94 | logAll("msg1", "msg2", "msg3"); 95 | //Arguments(3)["msg1","msg2","msg3"] 96 | 97 | //---------------- 98 | 99 | function getObject(){ 100 | return 101 | { 102 | } 103 | } 104 | 105 | getObject(); 106 | 107 | //---------------- 108 | 109 | function log(value){ 110 | console.log(value); 111 | } 112 | 113 | log(1); 114 | log("text"); 115 | log({message : "text"}); 116 | 117 | //---------------- 118 | 119 | let n = 1; 120 | typeof(n); //"number" 121 | 122 | let s = "text"; 123 | typeof(s); //"string" 124 | 125 | let fn = function() {}; 126 | typeof(fn); //"function" -------------------------------------------------------------------------------- /Chapter 13.txt: -------------------------------------------------------------------------------- 1 | const obj = { 2 | message : "discover" 3 | } 4 | 5 | obj.message; //"discover" 6 | 7 | //----------------------- 8 | 9 | const french = {}; 10 | french["Thank you"] = "Merci"; 11 | 12 | french["Thank you"]; //"Merci" 13 | 14 | //----------------------- 15 | 16 | const obj = {}; 17 | 18 | //Number as key 19 | obj[1] = "Number 1"; 20 | obj[1] === obj['1']; //true 21 | 22 | //Object as key 23 | const number1 = { 24 | toString : function() {return '1';} 25 | } 26 | obj[number1] === obj['1']; //true 27 | 28 | //----------------------- 29 | 30 | const book = { 31 | title : "How JavaScript Works", 32 | author : { 33 | firstName : "Douglas", 34 | lastName : "Crockford" 35 | } 36 | } 37 | 38 | //----------------------- 39 | 40 | const app = {}; 41 | 42 | app.authorGateway = { 43 | getAuthors : function() {} 44 | }; 45 | 46 | app.bookGateway = { 47 | getBooks : function() {} 48 | }; 49 | 50 | //----------------------- 51 | 52 | const timer = { 53 | secret: 0, 54 | start : function() {}, 55 | stop : function() {}, 56 | } 57 | 58 | timer.secret; //0 59 | timer.start = function() { 60 | console.log("don't start"); 61 | } 62 | timer.start(); //"don't start" 63 | 64 | //----------------------- 65 | 66 | const timerPrototype = { 67 | start : function() {}, 68 | stop : function() {} 69 | }; 70 | 71 | const timer = Object.create(timerPrototype); 72 | timer.__proto__ === timerPrototype; //true 73 | 74 | //----------------------- 75 | 76 | const timerPrototype = Object.freeze({ 77 | start : function() {}, 78 | stop : function() {} 79 | }); 80 | 81 | const timer = Object.create(timerPrototype); 82 | timer.start = function() { 83 | console.log("don't start"); 84 | } 85 | 86 | //----------------------- 87 | 88 | function Timer(){ 89 | this.secret = 0; 90 | } 91 | 92 | Timer.prototype = { 93 | start : function() {}, 94 | stop : function() {} 95 | } 96 | 97 | const timer = new Timer(); 98 | timer.start(); 99 | 100 | //----------------------- 101 | 102 | function newTimer(){ 103 | let newObj = Object.create(Timer.prototype); 104 | let returnObj = Timer.call(newObj, arguments); 105 | if(returnObj) return returnObj; 106 | 107 | return newObj; 108 | } 109 | 110 | //----------------------- 111 | 112 | class Timer{ 113 | constructor(){ 114 | this.secret = 0; 115 | } 116 | 117 | start() {} 118 | stop() {} 119 | } 120 | 121 | const timer = new Timer(); 122 | timer.__proto__ === Timer.prototype; 123 | 124 | //----------------------- 125 | 126 | function logProperty(name){ 127 | console.log(name); //property name 128 | console.log(obj[name]); //value 129 | } 130 | 131 | Object.keys(obj).forEach(logProperty); -------------------------------------------------------------------------------- /Chapter 02.txt: -------------------------------------------------------------------------------- 1 | let x = 1; 2 | { 3 | let x = 2; 4 | } 5 | console.log(x); //1 6 | 7 | //---------------- 8 | 9 | var x = 1; 10 | { 11 | var x = 2; 12 | } 13 | console.log(x); //2 14 | 15 | //---------------- 16 | 17 | //module "./TodoStore.js" 18 | export default function TodoStore(){} 19 | 20 | //module "./UserStore.js" 21 | export default function UserStore(){} 22 | 23 | 24 | //module "./main.js" 25 | import TodoStore from "./TodoStore"; 26 | import UserStore from "./UserStore"; 27 | const todoStore = TodoStore(); 28 | const userStore = UserStore(); 29 | 30 | //---------------- 31 | 32 | //module "./tools.js" 33 | export function compose(...args){} 34 | export function decorate(f, ...args){} 35 | 36 | 37 | //module "./main.js" 38 | import { compose, decorate } from "./tools"; 39 | 40 | //---------------- 41 | 42 | const numbers = [1, 2, 3]; 43 | const arr = ['a', 'b', 'c', ...numbers]; 44 | 45 | console.log(arr); 46 | //["a", "b", "c", 1, 2, 3] 47 | 48 | //---------------- 49 | 50 | function process(x,y, ...arr){ 51 | console.log(arr) 52 | } 53 | 54 | process(1, 2, 3, 4, 5); 55 | //[3, 4, 5] 56 | 57 | function processArray(...arr){ 58 | console.log(arr) 59 | } 60 | 61 | processArray(1, 2, 3, 4, 5); 62 | //[1, 2, 3, 4, 5] 63 | 64 | //---------------- 65 | 66 | const book = { title: "JavaScript: The Good Parts" }; 67 | 68 | //clone with Object.assign() 69 | const clone = Object.assign({}, book); 70 | 71 | //clone with spread operator 72 | const clone = { ...book }; 73 | 74 | const arr = [1, 2 ,3]; 75 | 76 | //clone with slice() 77 | const cloneArr = arr.slice(); 78 | 79 | //clone with spread operator 80 | const cloneArr = [ ...arr ]; 81 | 82 | //---------------- 83 | 84 | const authorGateway = { 85 | getAuthors: function() {}, 86 | editAuthor: function() {} 87 | }; 88 | 89 | const bookGateway = { 90 | getBooks: function() {}, 91 | editBook: function() {} 92 | }; 93 | 94 | //copy with Object.assign() 95 | const gateway = Object.assign({}, 96 | authorGateway, 97 | bookGateway); 98 | 99 | //copy with spread operator 100 | const gateway = { 101 | ...authorGateway, 102 | ...bookGateway 103 | }; 104 | 105 | //---------------- 106 | 107 | const part1 = [1, 2, 3]; 108 | const part2 = [4, 5, 6]; 109 | 110 | //concatenate with concat() 111 | const arr = part1.concat(part2); 112 | 113 | //concatenate with spread operator 114 | const arr = [...part1, ...part2]; 115 | 116 | console.log(arr); 117 | //[1, 2, 3, 4, 5, 6] 118 | 119 | //---------------- 120 | 121 | function logAll(...args){ 122 | console.log(args); 123 | } 124 | 125 | logAll("msg1", "msg2", "msg3"); 126 | //["msg1", "msg2", "msg3"] 127 | 128 | //---------------- 129 | 130 | function BookGateway(){ 131 | function getBooks() {} 132 | function editBook() {} 133 | 134 | return { 135 | getBooks: getBooks, 136 | editBook: editBook 137 | } 138 | } 139 | 140 | 141 | function BookGateway(){ 142 | function getBooks() {} 143 | function editBook() {} 144 | 145 | return { 146 | getBooks, 147 | editBook 148 | } 149 | } 150 | 151 | //---------------- 152 | 153 | const todoStore = TodoStore(); 154 | const userStore = UserStore(); 155 | 156 | const stores = { 157 | todoStore, 158 | userStore 159 | }; 160 | 161 | //---------------- 162 | 163 | function TodoStore(args){ 164 | const helper = args.helper; 165 | const dataAccess = args.dataAccess; 166 | const userStore = args.userStore; 167 | } 168 | 169 | 170 | function TodoStore(args){ 171 | const { 172 | helper, 173 | dataAccess, 174 | userStore } = args; 175 | } 176 | 177 | 178 | function TodoStore({helper, dataAccess, userStore}){} 179 | 180 | 181 | TodoStore({ 182 | helper: {}, 183 | dataAccess: {}, 184 | userStore: {} 185 | }); 186 | 187 | //---------------- 188 | 189 | function log(message, mode = "Info"){ 190 | console.log(mode + ": " + message); 191 | } 192 | 193 | log("An info"); 194 | //Info: An info 195 | 196 | log("An error", "Error"); 197 | //Error: An error 198 | 199 | //---------------- 200 | 201 | function createTodoItemHtml(todo){ 202 | return `
  • 203 |
    ${todo.title}
    204 |
    ${todo.userName}
    205 |
  • `; 206 | } 207 | 208 | //---------------- 209 | 210 | class Service { 211 | doSomething(){ 212 | console.log("do-something"); 213 | } 214 | } 215 | 216 | const service = new Service(); 217 | console.log(service.__proto__ === Service.prototype); 218 | 219 | //---------------- 220 | 221 | class Service { 222 | doSomething(){ 223 | console.log("do-something"); 224 | } 225 | } 226 | 227 | class SpecialService extends Service { 228 | doSomethingElse(){ 229 | console.log("do-something-else"); 230 | } 231 | } 232 | 233 | const specialService = new SpecialService(); 234 | specialService.doSomething(); 235 | specialService.doSomethingElse(); 236 | 237 | //---------------- 238 | 239 | const todos = [ 240 | {id: 1, title: "learn", type:"NC", completed: false}, 241 | {id: 2, title: "connect", type:"RC", completed: true} 242 | ]; 243 | 244 | const titles = todos.map(todo => todo.title); 245 | //["learn", "connect"] 246 | 247 | 248 | const filteredTodos = todos.filter(todo => !todo.completed); 249 | //{id: 1, title: "learn", type: "NC", completed: false} 250 | 251 | //---------------- 252 | 253 | function isNewContent(todo){ 254 | return todo.type === "NC"; 255 | } 256 | 257 | const isNewContent = todo => todo.type === "NC"; 258 | 259 | //---------------- 260 | 261 | this.message = "help"; 262 | 263 | const logMessage = ()=>{ 264 | console.log(this.message); 265 | } 266 | 267 | logMessage(); //"help" 268 | logMessage.call({message : "identify"}); //"help" 269 | 270 | //---------------- 271 | 272 | function print(from, to) 273 | { 274 | const n = from; 275 | if (n > to) return; 276 | 277 | console.log(n); 278 | 279 | //last statement is the recursive call 280 | print(n + 1, to); 281 | } 282 | 283 | print(1, 3); 284 | //1 285 | //2 286 | //3 287 | 288 | //---------------- 289 | 290 | function delay(duration) { 291 | return new Promise(function(resolve, reject){ 292 | setTimeout(resolve, duration); 293 | }); 294 | } 295 | 296 | function logMessage(){ 297 | console.log("process ended"); 298 | } 299 | 300 | delay(5000) 301 | .then(logMessage); 302 | 303 | //---------------- 304 | 305 | function fetchUsers(){ 306 | return fetch("/users"); 307 | } 308 | 309 | function doSomething(){ } 310 | function handleError(error){ } 311 | 312 | fetchUsers() 313 | .then(doSomething) 314 | .catch(handleError); --------------------------------------------------------------------------------