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

Understand spread operators cltJS

Understand spread operators cltJS

Mark Pedrotti

February 18, 2016
Tweet

More Decks by Mark Pedrotti

Other Decks in Programming

Transcript

  1. Understand spread operators, 
 which are new in ES2015. You

    type three dots ... It looks like an ellipsis.
  2. Understand spread operators Within a literal array, ...array 
 means

    “spread out” its elements. For example, [0, ...[1, 2], 3, 4] means [0, 1, 2, 3, 4]
  3. Goals for spread operators • Prefer declarative to imperative. •

    Describe what instead of tell how. • Write more literal notation, 
 call fewer array methods.
  4. Use cases for spread operators 1. Concatenate arrays 2. Remove

    an element 3. Append zero or more elements 4. Append one element 5. Replace an element
  5. Use cases for spread operators 1. Concatenate [0, 1] [2]

    [3, 4] [0, 1, 2, 3, 4] 2. Remove [0, 1, 2] 1 ! ∅ [0, 2] 3. Append [0, 1] [2, 3] [0, 1, 2, 3] 4. Append one [0, 1] 2 [0, 1, 2] 5. Replace [0, 1, 2] 1 ! 7 [0, 7, 2]
  6. Learning modes in examples • A diagram for visual learners.

    • A test case for symbolic learners. • JavaScript code in ES2015 
 with equivalent ES5
  7. Color theme in examples 
 Skookum autumn • yellow strong

    or emphasis • orange ES2015 emphasis • red ES5 emphasis • gray test de-emphasis
  8. 1. Concatenate arrays 
 into one array Given arrays of

    cards by suit, 
 return one array of cards.
  9. // Given arrays of cards by suit, return one array

    of cards. ♥ ♣ ♠ A ♥ 7 ♥ 6 ♥ 10 ♣ 9 ♣ 5 ♣ 2 ♣ J ♠ 9 ♠ 8 ♠ 8 ♠ 7 ♠ 5 ♠ 2 ♠
  10. // Given arrays of cards by suit, return one array

    of cards. // describe('a hand of cards as one array', () => { // it('is the concatenation of the arrays by suit', () => { // const hearts = ['A♥', '7♥', '6♥']; // const diamonds = []; // const clubs = ['10♣', '9♣', '5♣', '2♣']; // const spades = ['J♠', '9♠', '8♠', '7♠', '5♠', '2♠']; // const hand = {hearts, diamonds, clubs, spades}; // const cards = ['A♥', '7♥', '6♥', '10♣', '9♣', '5♣', '2♣', // 'J♠', '9♠', '8♠', '7♠', '5♠', '2♠']; // expect(cardsOfHand(hand).to.deep.equal(cards); // }); // });
  11. // Given arrays of cards by suit, return one array

    of cards. // ES2015 const // ES2015 destructuring an argument of a function // ES2015 arrow function: implicit return without block // ES2015 spread operator const cardsOfHand = ({hearts, diamonds, clubs, spades}) => [...hearts, ...diamonds, ...clubs, ...spades]; // ES5 // var cardsOfHand = function (hand) { // return [].concat(hand.hearts, hand.diamonds, // hand.clubs, hand.spades); // };
  12. Redux reducers give examples 
 of spread operators • hands

    in card games 
 state includes arrays of cards • todos list 
 state is an array of todo items
  13. Redux reducers have a type
 (statePrev, action) => stateNext •

    Given the previous state of an app • and an action object, • return the next state.
  14. Redux reducers have a type
 (statePrev, action) => stateNext like

    callbacks of array.reduce (valuePrev, element) => valueNext
  15. Redux reducers are pure functions • same inputs => same

    outputs • do not cause side effects • do not depend on side effects
  16. Redux reducers must never ever • change (mutate) previous state

    • cause side effects 
 API calls or route transitions • call non-pure functions 
 Date.now or Math.random
  17. Redux reducers therefore • return state as immutable data •

    to keep previous states of an app • because undo gives better user and developer experience UX/DX
  18. Redux reducer for card games:
 state includes arrays of cards

    A ♥ 7 ♥ 6 ♥ 10 ♣ 9 ♣ 5 ♣ 2 ♣ J ♠ 9 ♠ 8 ♠ 8 ♠ 7 ♠ 5 ♠ 2 ♠
  19. // The state of Hearts, an evasion-type trick-taking card game,

    // includes the hand of each player, which is an object // whose properties are arrays of cards by suit: // { // hearts: ['A♥', '7♥', '6♥'], // diamonds: [], // clubs: ['10♣', '9♣', '5♣', '2♣'], // spades: ['J♠', '9♠', '8♠', '7♠', '5♠', '2♠'] // }
  20. // Given the previous state and an action, return the

    next state. const hand = (state, action) => { switch (action.type) { case REMOVE_CARD: return handRemove(state, action.card); // 2. Remove case APPEND_CARDS: return handAppend(state, action.cards); // 3. Append default: return state; } }; // const hand = function (state, action) { … };
  21. 2. Remove an element 
 from an array Given an

    array of cards by suit 
 and a card, return the remaining cards.
  22. // Given an array of cards by suit and a

    card 10 ♣ 9 ♣ 5 ♣ 2 ♣
  23. // Given an array of cards by suit and a

    card, // return the remaining cards. 10 ♣ 9 ♣ 5 ♣ 2 ♣ 10 ♣ 9 ♣ 5 ♣
  24. // Given an array of cards by suit and a

    card, // return the remaining cards. // describe('remaining cards of a suit after a trick', () => { // it('doesn’t have the card because it is of the suit', () => { // const cards = ['10♣', '9♣', '5♣', '2♣']; // const card = '2♣'; // const cardsNext = ['10♣', '9♣', '5♣']; // expect(removeCard(cards, card).to.deep.equal(cardsNext); // }); // });
  25. // Given an array of cards by suit and a

    card, // return the remaining cards. // describe('remaining cards of a suit after a trick', () => { // it('doesn’t have the card because it isn’t of the suit', () => { // const cards = ['A♥', '7♥', '6♥']; // const card = '2♣'; // expect(removeCard(cards, card).to.equal(cards); // }); // });
  26. // Given an array of cards by suit and a

    card, // return the remaining cards. // ES2015 arrow function: explicit return from block const removeCard = (cards, card) => { const index = cards.indexOf(card); return index === -1 ? cards : [...cards.slice(0, index), ...cards.slice(index + 1)] };
  27. 3. Append zero or more elements 
 to the end

    of an array Given an array of cards by suit 
 and an array of cards received, return the cards merged in order.
  28. // Given an array of cards by suit and an

    array of cards received 9 ♣ 2 ♣ 10 ♣ 5 ♣
  29. // Given an array of cards by suit and an

    array of cards received, // return the cards 9 ♣ 2 ♣ 10 ♣ 5 ♣ 9 ♣ 2 ♣ 10 ♣ 5 ♣
  30. // Given an array of cards by suit and an

    array of cards received, // return the cards merged in order. 9 ♣ 2 ♣ 10 ♣ 5 ♣ 10 ♣ 9 ♣ 5 ♣ 2 ♣
  31. // Given an array of cards by suit and an

    array of cards received, // return the cards merged in order. // describe('cards of a suit after receiving passed cards', () => { // it('includes the passed cards and is sorted descending', () => { // const cards = ['9♣', '2♣']; // const cardsAdded = ['10♣', '5♣']; // const cardsNext = ['10♣', '9♣', '5♣', '2♣']; // expect(addCards(cards, cardsAdded).to.deep.equal(cardsNext); // }); // });
  32. // Given an array of cards by suit and an

    array of cards received, // return the cards merged in order. // describe('cards of a suit after receiving passed cards', () => { // it('remains the same because none are of the suit', () => { // const cards = ['A♥', '7♥', '6♥']; // const cardsAdded = []; // received no hearts // expect(addCards(cards, cardsAdded).to.equal(cards); // }); // });
  33. // Given an array of cards by suit and an

    array of cards received, // return the cards merged in order. const addCards = (cards, cardsAdded) => return cardsAdded.length === 0 ? cards : [...cards, ...cardsAdded].sort(compareCards);
  34. Specific resources: Redux reducers, ... • http://redux.js.org/docs/basics/Reducers.html • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Operators/Spread_operator#A_more_powerful_array_literal

    Prerequisites: const, destructuring, arrow functions, findIndex • http://www.2ality.com/2015/02/es6-scoping.html • http://exploringjs.com/es6/ch_parameter-handling.html#leanpub-auto- examples-of-destructuring-in-parameter-handling • http://www.2ality.com/2012/04/arrow-functions.html • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Global_Objects/Array/findIndex
  35. // Given the previous state and an action, return the

    next state. const todos = (state, action) => { switch (action.type) { case ADD_TODO: return todosAdd(state, action.text); // 4. Append case COMPLETE_TODO: return todosComplete(state, action.index); // 5. Replace default: return state; } }; // const todos = function (state, action) { … };
  36. 4. Append one element 
 to the end of an

    array Given the previous state 
 and text to add, 
 return the next state.
  37. // Given the previous state and an action // [

    // ] // {type: ADD_TODO, text: 'Append one element'}
  38. // Given the previous state and an action, return the

    next state. // [ // ] // {type: ADD_TODO, text: 'Append one element'} // [ // {text: 'Append one element', completed: false} // ]
  39. // Given the previous state // [ // {text: 'Append

    one element', completed: false} // ]
  40. // Given the previous state and an action // [

    // {text: 'Append one element', completed: false} // ] // {type: ADD_TODO, text: 'Replace an element'}
  41. // Given the previous state and an action, return the

    next state. // [ // {text: 'Append one element', completed: false} // ] // {type: ADD_TODO, text: 'Replace an element'} // [ // {text: 'Append one element', completed: false}, // {text: 'Replace an element', completed: false} // ]
  42. // Given the previous state and text to add, return

    the next state. // ES2015 object literal shortcut const todosAdd = (state, text) => [...state, {text, completed: false}]; // ES3 push changes (mutates) the previous state // Redux reducer MUST :-| NEVER :-/ EVER :-( // var todosAdd = function (state, text) { // state.push({text: text, completed: false}); // return state; // }
  43. // Given the previous state and text to add, return

    the next state. // ES2015 object literal shortcut const todosAdd = (state, text) => [...state, {text, completed: false}]; // ES3 concat returns a “shallow copy” of the previous state :-) // That is, a different array which consists of the same elements, // plus the element which was added. // var todosAdd = function (state, text) { // return state.concat({text: text, completed: false}); // }
  44. • When the state changes, 
 make a shallow copy

    of objects, • so that, after the state changes, 
 a shallow comparison of objects
 with JavaScript strict equality === 
 answers “What’s the delta?” 
 What did and did not change?
  45. 5. Replace an element 
 in an array Given previous

    state 
 and index to complete, 
 return next state.
  46. // Given the previous state // [ // {text: 'Append

    one element', completed: false}, // {text: 'Replace an element', completed: false} // ]
  47. // Given the previous state and an action // [

    // {text: 'Append one element', completed: true}, // {text: 'Replace an element', completed: false} // ] // {type: COMPLETE_TODO, index: 0}
  48. // Given the previous state and an action, return the

    next state. // [ // {text: 'Append one element', completed: false}, // {text: 'Replace an element', completed: false} // ] // {type: COMPLETE_TODO, index: 0} // [ // {text: 'Append one element', completed: true}, // {text: 'Replace an element', completed: false} // ]
  49. // Given the previous state // [ // {text: 'Append

    one element', completed: true}, // {text: 'Replace an element', completed: false} // ]
  50. // Given the previous state and an action // [

    // {text: 'Append one element', completed: true}, // {text: 'Replace an element', completed: false} // ] // {type: COMPLETE_TODO, index: 1}
  51. // Given the previous state and an action, return the

    next state. // [ // {text: 'Append one element', completed: true}, // {text: 'Replace an element', completed: false} // ] // {type: COMPLETE_TODO, index: 1} // [ // {text: 'Append one element', completed: true}, // {text: 'Replace an element', completed: true} // ]
  52. // Given previous state and index to complete, return next

    state. // ES2015 Object.assign // Replace the completed item with a “shallow copy” of the object. // That is, a different object whose properties have the same values, // except completed. const todosComplete = (state, index) => [ ...state.slice(0, index), Object.assign({}, state[index], {completed: true}), ...state.slice(index + 1) ];
  53. Specific resources: todos list • http://todomvc.com • https://github.com/reactjs/redux/tree/master/examples/todos Prerequisites: literal

    object shortcut, Object.assign • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Operators/Object_initializer#Property_definitions • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Global_Objects/Object/assign
  54. General resources: Redux, Mocha, Chai • https://github.com/reactjs/redux • http://mochajs.org/ •

    http://chaijs.com/ General resources: ES2015 • https://developer.mozilla.org/en-US/docs/Web/JavaScript/ New_in_JavaScript/ECMAScript_6_support_in_Mozilla • https://www.webkit.org/blog/4054/es6-in-webkit/ • https://babeljs.io/docs/learn-es2015/ • http://www.2ality.com/2015/10/es6-feature-lists.html • https://twitter.com/JavaScriptDaily