Modern JS Concepts

Pure Functions

A pure function's return value is determined only by its input values (arguments) with no side effects.

function half(x) {
  return x / 2;
}

half(8) === 4

Referential transparency

Pure Functions

Pure functions must take arguments.


The same input (arguments) will always produce the same output (return).


Pure functions rely only on local state and do not mutate external state (note: console.log changes global state).


Pure functions do not produce side effects.


Pure functions cannot call impure functions.

Impure Functions

An impure function mutates state outside its scope. Any function that has side effects  is impure.

// impure function producing a side effect
function showAlert() {
  alert('This is a side effect!');
}

// impure function mutating external state
var globalVal = 1;
function incrementGlobalVal(x) {
  globalVal += x;
}

// impure function that resembles a pure function,
// but returns different results given the same inputs
function getRandomRange(min, max) {
  return Math.random() * (max - min) + min;
}

Purity Takeaways

impure functions that procedurally invoke pure functions.

advantages for testing and immutability

Referential transparency enables memoization

It can be a challenge to determine when functions are truly pure.

State

State refers to the information a program has access to and can operate on at a point in time.

Stateful

Stateful programs, apps, or components store data in memory about the current state. They can modify the state as well as access its history.

var number = 1;
function increment() {
  return number++;
}
increment(); 

Stateless

Stateless functions or components perform tasks as though running them for the first time, every time. This means they do not reference or utilize any information from earlier in their execution.

var number = 1;
function increment(n) {
  return n + 1;
}
increment(number); 

State Takeaways

State management is important for any complex application. 

Stateful functions or components modify state and store history, but are more difficult to test and debug.

A stateless program returns new state rather than modifying existing state.

Immutability 

If an object is immutable, its value cannot be modified after creation.

In JavaScript, strings and number literals are immutable by design.

Mutable

If an object is mutable, its value can be modified after creation.

Objects  are mutable by design.

Immutability in JavaScript

JavaScript objects can also be frozen with Object.freeze(obj) to make them immutable. 

shallow

we can return a new state object each time the object changes.

deep-freeze

immutable.js

Immutability Takeaways

Immutability results in code that is simpler to reason about.

 many algorithms and operations cannot be implemented efficiently.

Immutability enables persistency.

Imperative and Declarative

JavaScript can support both programming paradigms.

Imperative programming describes how a program's logic works in explicit commands with statements that modify the program state. eg. for

Declarative programming describes what a program's logic accomplishes withoutdescribing how. eg. Array.each

Imperative and Declarative Programming Takeaways

Declarative programming has obvious advantages with regard to brevity and readability, but at the same time it can feel magical.

Higher-order Functions

A higher-order function is a function that:

 

accepts another function as an argument,

 

or


returns a function as a result.

Functional Programming

Functional programming encompasses the above concepts in the following ways:

Core functionality is implemented using pure functions without side effects.


Data is immutable.


Functional programs are stateless.


Imperative container code manages side effects and executes declarative, pure core code.

const fpCopy = `Functional programming is powerful and enjoyable to write. It's very cool!`;

// remove punctuation from string 
const stripPunctuation = (str) =>
  str.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '');

// split passed string on spaces to create an array
const getArr = (str) =>
  str.split(' ');

// count items in the passed array
const getWordCount = (arr) =>
  arr.length;

// find items in the passed array longer than 5 characters
// make items lower case
const getKeywords = (arr) =>
  arr
    .filter(item => item.length > 5)
    .map(item => item.toLowerCase());

// process copy to prep the string, create an array, count words, and get keywords
function processCopy(str, prepFn, arrFn, countFn, kwFn) {
  const copyArray = arrFn(prepFn(str));

  console.log(`Word count: ${countFn(copyArray)}`);
  console.log(`Keywords: ${kwFn(copyArray)}`);
}

processCopy(fpCopy, stripPunctuation, getArr, getWordCount, getKeywords);

Functional Programming Takeaways

Immutable data and statelessness mean that the program's existing state is not modified. Instead, new values are returned.

Pure functions are used for core functionality. In order to implement the program and handle necessary side effects, impure functions can call pure functions imperatively.

Observables

subscribe to observables and react to events emitted by streams

Observables example

const resize$ = 
  Rx.Observable
    .fromEvent(window, 'resize')
    .throttleTime(350);

const subscription = 
  resize$.subscribe((event) => {
    let t = event.target;
    console.log(`${t.innerWidth}px x ${t.innerHeight}px`);
  });

Resizing the browser window emits a stream of events over a period of time as the window is dragged to its desired size. We can create an observable and subscribe to it to react to the stream of resize events

Hot Observables

User interface events are hot.

Hot Observables will always push even if we're not specifically reacting to them with a subscription.

Cold Observables

cold Observables begins pushing only when we subscribe to it. If we subscribe again, it will start over.

const source$ = Rx.Observable.range(1, 5);

// subscribe to source$ observable
const subscription = source$.subscribe(
  (value) => { console.log(`Next: ${value}`); }, // onNext
  (event) => { console.log(`Error: ${event}`); }, // onError
  () => { console.log('Completed!'); }  // onCompleted
);

Observables Takeaways

Observables are streams. We can observe any stream

Reactive Programming

Reactive programming is concerned with propagating and responding to incoming events over time, declaratively (describing what to do rather than how).

Reactive Programming with JavaScript

<input id="confirmation-code" type="text">
<p>
  <strong>Valid code attempt:</strong>
  <code id="attempted-code"></code>
</p>
const confCodeInput = document.getElementById('confirmation-code');
const attemptedCode = document.getElementById('attempted-code');

const confCodes$ = 
  Rx.Observable
    .fromEvent(confCodeInput, 'input')
    .map(e => e.target.value)
    .filter(code => code.length === 6);

const subscription = confCodes$.subscribe(
  (value) => attemptedCode.innerText = value,
  (event) => { console.warn(`Error: ${event}`); },
  () => { console.info('Completed!'); }
);

Reactive Programming Takeaways

The reactive programming paradigm involves observing and reacting to events in asynchronous data streams.

deck

By Joson Chen

deck

  • 218