Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pure Functions: An Introduction to Functional Programming in JavaScript

Pure Functions: An Introduction to Functional Programming in JavaScript

Pure functions are the foundation of functional programming. Using pure functions can make application development in JavaScript easier. But what is a pure function? In this session, you'll learn what pure functions are and how you can use them to simplify your development process. In addition, we'll look at using pure functions to build applications in JavaScript with React and Redux.

Jonathan Kemp

October 22, 2016
Tweet

More Decks by Jonathan Kemp

Other Decks in Programming

Transcript

  1. PURE FUNCTIONS • Many beneficial properties • Foundation of functional

    programming • Small, reusable, predictable • Building blocks
  2. f(x) = x * 2 f(2) = 2 * 2

    = 4 f(3) = 3 * 2 = 6 f(4) = 4 * 2 = 8
  3. function double(x) { return x * 2; } console.log( double(2)

    ); // 4 console.log( double(3) ); // 6 console.log( double(4) ); // 8
  4. SIDE EFFECTS A side effect is a change that is

    not local to the function that caused it.
  5. function double(x) { return x * 2; } console.log( double(2)

    ); // 4 console.log( double(3) ); // 6 console.log( double(4) ); // 8
  6. ARRAY METHODS • Destructive array methods vs. Non-destructive array methods

    • Destructive methods should be avoided where possible • Concat should be used instead of push. • Other non-destructive array methods: map, filter, and reduce.
  7. const array = [1, 2, 3]; const newArray = array.push(4);

    console.log(array); // [1, 2, 3, 4]
  8. const array = [1, 2, 3]; const newArray = array.concat([4]);

    console.log(array); // [1, 2, 3] console.log(newArray); // [1, 2, 3, 4]
  9. OBJECT.ASSIGN • Copies the properties of source objects into a

    target object and then returns it. • Use Object.assign to avoid directly editing objects.
  10. OBJECT.FREEZE • The object is made effectively immutable. • Prevents

    new properties from being added to it. • Prevents existing properties from being removed. • Prevents existing properties, or their enumerability, configurability, or writability, from being changed.
  11. PURE FUNCTIONS • No shared state • No side effects

    • Much less likely to cause bugs
  12. function getPath(path) { var urlPrefix = 'https://atlassian.net/browse/', validPath = path.trim();

    return urlPrefix + validPath; } function newTab(path) { chrome.tabs.create({url: getPath(path)}); }
  13. function getPath(path) { var urlPrefix = 'https://atlassian.net/browse/', validPath = path.trim();

    return urlPrefix + validPath; } function newTab(path) { chrome.tabs.create({url: getPath(path)}); }
  14. function getPath(path) { var urlPrefix = 'https://atlassian.net/browse/', validPath = path.trim();

    return urlPrefix + validPath; } function newTab(path) { chrome.tabs.create({url: getPath(path)}); }
  15. BENEFITS OF PURE FUNCTIONS • Easier to unit test •

    Easier to debug • Easier to understand • Self-documenting • Reusable
  16. function getIDsFromPrompt() { var ids, input = window.prompt('Enter the number:');

    if (/,/.test(input)) { ids = input.split(','); } else { ids = [ input ]; } return ids; }
  17. function getIDsFromPrompt() { var ids, input = window.prompt('Enter the number:');

    if (/,/.test(input)) { ids = input.split(','); } else { ids = [ input ]; } return ids; }
  18. function getPath(id) { var urlPrefix = 'https://atlassian.net/browse/', validId = id.trim();

    return urlPrefix + validId; } function newTab(url) { chrome.tabs.create({url: url}); } function openJIRAinNewTabs() { var jiraIds = getIDsFromPrompt(), jiraURLs = jiraIds.map(getPath); jiraURLs.forEach(newTab); }
  19. function getPath(id) { var urlPrefix = 'https://atlassian.net/browse/', validId = id.trim();

    return urlPrefix + validId; } function newTab(url) { chrome.tabs.create({url: url}); } function openJIRAinNewTabs() { var jiraIds = getIDsFromPrompt(), jiraURLs = jiraIds.map(getPath); jiraURLs.forEach(newTab); }
  20. const EntryList = (props) => { return <ul>{props.items.map((itemText, i) =>

    { return <li key={i + itemText}>{itemText}</li>; })}</ul>; };
  21. const EntryList = (props) => { return <ul>{props.items.map((itemText, i) =>

    { return <li key={i + itemText}>{itemText}</li>; })}</ul>; };
  22. const EntryList = (props) => { return <ul>{props.items.map((itemText, i) =>

    { return <li key={i + itemText}>{itemText}</li>; })}</ul>; };
  23. const EntryList = (props) => { return <ul>{props.items.map((itemText, i) =>

    { return <li key={i + itemText}>{itemText}</li>; })}</ul>; };
  24. const EntryList = (props) => { return <ul>{props.items.map((itemText, i) =>

    { return <li key={i + itemText}>{itemText}</li>; })}</ul>; };
  25. STATELESS COMPONENTS • Must not retain internal state • Do

    not have backing instances • Do not have the component lifecycle methods
  26. REDUX 1. State of your app is stored in an

    object tree inside a single store. 2. Only way to change the state tree is to emit an action. 3. Specify how the actions transform the state tree with pure reducers.
  27. import { createStore } from 'redux' function counter(state = 0,

    action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } let store = createStore(counter) store.subscribe(() => console.log(store.getState()) )
  28. import { createStore } from 'redux' function counter(state = 0,

    action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } let store = createStore(counter) store.subscribe(() => console.log(store.getState()) )
  29. import { createStore } from 'redux' function counter(state = 0,

    action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } let store = createStore(counter) store.subscribe(() => console.log(store.getState()) )
  30. import { createStore } from 'redux' function counter(state = 0,

    action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } let store = createStore(counter) store.subscribe(() => console.log(store.getState()) )
  31. REDUX • Reducers are pure. They don’t mutate state. They

    produce no side effects. Given the same input, they return the same output. • This makes it easer to reason about how state is changed. It’s easier to understand how the application works. • Benefits are largely the same as using pure functions.
  32. RESOURCES • Master the JavaScript Interview: What is a Pure

    Function? - Eric Elliott
 https://medium.com/javascript-scene/master-the- javascript-interview-what-is-a-pure-function- d1c076bec976#.765uz0xdn • Pure Functions (Video) - Eric Elliot
 https://vimeo.com/160326750