functional-javascript



functional-javascript

0 0


functional-javascript

A talk given at a local meetup

On Github AlecAivazis / functional-javascript

Functional JavaScript

Building Modern User Interfaces

alecaivazis.github.io/functional-javascript

Alec Aivazis

alec.aivazis.comgithub.com/AlecAivazis

roadmap

  • Basic modern javascript (es6) syntax
  • Functional JavaScript
  • Quick intro to functional React

Syntax

Variable Declaration

// hoisted, functionally scoped
var asdf = 'asdf'
// cannot be re-declared, block scoped
let foo = 'bar'
// cannot be changed (sometimes), block scoped
const bar = 'baz'

Better Mental Model

// cannot be re-declared
let foo = 'bar'
// cannot be changed (sometimes)
const bar = 'baz'

Functions

// does this act like a var, let,
// or const?
function myFunc(name) {
    return 'Hello ' + name
}
// now we can decide!
const myNewFunc = (name) => (
    'Hello ' + name
)

// sometimes implicit returns are bad
const myNewestFunc = (name) => {
    return 'Hello ' + name
}

destructuring

var data = {'key': 'bar'}
// grab the key entry
var key = data.key
function myFunc(args) {
    console.log(args.foo)
}
myFunc({foo: 'bar'})
const data = {'key': 'bar'}
// grab the key entry
const {key} = data
function myFunc({foo}) {
    console.log(foo)
}
myFunc({foo: 'bar'})

spread

var mockData = {
    foo: 'bar',
}
var newObject = Object.assign({},
    mockData,
    {
        'bar': 'baz'
    }
)
const mockData = {
    foo: 'bar',
}

const newObj = {
    ...mockData,
    'bar': 'baz',
}

Functional Programming

in

JavaScript

The Function Object

const myFunction = () => 'hello world'

console.log(myFunction)

combinators

map

[1,2,3][1,4,9]

In the imperative world...
// we want to square each number in this list
const numbers = [1,2,3]

// we'll collect the results in this list
const results = []

// visit each element in the array
for (const i = 0 ; i < numbers.length ; i ++) {
    // grab the i'th entry
    const entry = numbers[i]
    // add the square to the list
    result.append(entry * entry)
}

// results == [1, 4, 9]
With our fancy new combinator
// we want to square each number in this list
const numbers = [1,2,3]
// square each number in a single line!
const results = numbers.map(entry => entry * entry)

// results == [1, 4, 9]

filter

[1,2,3,4][2,4]

Then
// we want to grab every even number in this list
const numbers = [1,2,3,4,5,6]
// collect results here
const results = []

// go over every number
for (const i = 0 ; i < numbers.length ; i ++) {
    // grab the i'th number
    const number = numbers[i]
    // if the number is even
    if (number % 2 == 0) {
        // add it to the list
        results.append(number)
    }
}

// results == [2, 4, 6]

Now
// we want to grab every even number in this list
const numbers = [1,2,3,4,5,6]

// collect results here
const results = numbers.filter(entry => entry % 2 == 0)

// results == [2, 4, 6]

reduce

[1,2,3]6

The imperative way
// now we want to add each number in the list
const numbers = [1,2,3]

// start off at zero
const total = 0

// visit every item
for (const i = 0 ; i < numbers.length ; i ++) {
    // grab the i'th number
    const number = numbers[i]
    // add the number to the running total
    total += number
}

// total == 6
Using reduce,
// the numbers to sum up
const numbers = [1,2,3]

// combine them in a single line
const total = numbers.reduce((sum, entry) => sum + entry, 0)

// total == 6

building web interfaces

HTML

<div>
    <button id="button">
        hello
    </button>
</div>

jQuery

<div>
    <button id="button">
        hello
    </button>
</div>
$("#button").on('click', (event) => {
    this.style('color', 'red')
})

ReactNow that we've covered the functional basics, let's build some UIs.Used to be imperativeNow is functional
 
React's entire philosophy is based around making javascript the single tool in the web developer's toolkit.
<div>
    <div class="navigation">
        <ul>
            <li> nav1 </li>
            <li> nav2 </li>
            <li> nav3 </li>
        </ul>
    </div>
    <div class="content">
    </div>
    <div class="footer">
    </div>
</div>

<script src="app.js">
<div>
    <Navigation>
    <Content>
    <Footer>
</div>

More syntax!

In order to do that, we first have to cover some more syntax
import React from 'react'
import ReactDom from 'react-dom'
const MyElement = () => (
    <div>
        hello world!
    </div>
)
// rendered with <MyElement />
// render over a specific element
ReactDom.render(<MyElement />, document.getElementById('app'))
// rendered with <MyElement />
mention jsx as an extension of javascript adding syntactic sugar this makes rendering our custom elements feel very natural alongside the standard html one in order to actually render our component tree, we have to do so over a single element

inline expressions

const name = "John"

const MyElement = () => (
    <div>
        Hello {name}!
    </div>
)

// rendered with <MyElement />
in order for the compiler to know that an expression should be evaluated as javascript, you have to wrap it in curly braces.

passing data

const MyElement = ({name}) => (
    <div>
        Hello {name}!
    </div>
)

// rendered with <MyElement name="John"/>


I mean, not only does it make it pretty easy to reason about your interface as pure elements But because everything is pure, there's no need for extreme unit testing and shooting for 100% coverage. You only really need to worry about how your data source changes and the components with complicated display logic.However, it gets even cooler when we start mixing in our functional combinators

using map in jsx

// <MyElement numbers={[1,2,3]} />
const NumberList = (numbers) => (
    <ul>
        { numbers.map(number => (
            <li>
                {number}
            </li>
        ))}
    </ul>
)
Let's consider the example where I want to take a list of numbers and show an html list composed of ul and li elements with each entry as the square of the numbers in this list This is easily accomplished using an inline map over the numbers prop. But our functional tools don't stop becoming useful after mapping over lists

putting it all together

const itemsInCart = [{name: 'Steak', price: 25.75}, ...]
// the root shopping cart component
const ShoppingCart = (items) => {
    // figure out the total cost of all the recipes
    const totalCost = items.reduce((sum, {price}) => sum + price, 0)
    // render the component
    return (
        <div>
            {items.map(cartItem => (
                <ShoppingCartItem {...cartItem}/>
            ))}
            <div>
                Total cost: {totalCost}
            </div>
        </div>
    )
}

// rendered with <ShoppingCart items={itemsInCart} />
const itemsInCart = [{name: 'Steak', price: 25.75}, ...]

// ...
const totalCost = items.reduce((sum, {price}) => sum + price, 0)

// ...
<div>
    {totalCost}
</div>
const itemsInCart = [{name: 'Steak', price: 25.75}, ...]

// ...
{items.map(cartItem => (
    <ShoppingCartItem {...cartItem}/>
))}
// ...
const ShoppingCartItem = ({name, date}) => (
    <div>
        <div> {name} </div>
        <div> {date} </div>
    </div>
)
Thanks!
Functional JavaScriptBuilding Modern User Interfacesalecaivazis.github.io/functional-javascript