├── 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);
--------------------------------------------------------------------------------