React: Difference between revisions

6,073 bytes added ,  1 October 2019
functional programming with JavaScript heading
Line 518: Line 518:


= Functional Programming with JavaScript =
= Functional Programming with JavaScript =
== What it means to be functional ==
JavaScript functions are first-class citizens -- they can do the same things that variables can do.  Functions can represent data. e.g.
<source lang="js">
var log = function(msg) {
  console.log(msg);
}
log("In JS functions are variables");
// equivalent to
const log = msg => { console.log(msg); };
</source>
we can add them to objects:
<source lang="js">
const obj = {
  msg: "they can be added to objects like variables",
  log(msg) { console.log(msg); }
};
obj.log(obj.msg);
</source>
add them to arrays:
<source lang="js">
const messages = [
  "They can be inserted into arrays",
  message => console.log(message),
  "like variables",
  message => console.log(message)
];
messages[1](messages[0]); // They can be inserted into arrays
messages[3](messages[2]); // like variables
</source>
send to other functions as arguments:
<source lang="js">
const insideFn = logger => {
  logger("They can be sent to other functions as arguments");
};
insideFn(message => console.log(message));
// They can be sent to other functions as arguments
</source>
returned from other functions:
<source lang="js">
const createScream = function(logger) {
  return function(message) {
    logger(message.toUpperCase() + "!!!");
  };
};
const scream = createScream(message => console.log(message));
scream("functions can be returned from other functions");
scream("createScream returns a function");
scream("scream invokes that returned function");
// FUNCTIONS CAN BE RETURNED FROM OTHER FUNCTIONS!!!
// CREATESCREAM RETURNS A FUNCTION!!!
// SCREAM INVOKES THAT RETURNED FUNCTION!!!
// equivalent to (using arrows)
const createScream = logger => message => {
  logger(message.toUpperCase() + "!!!");
};
// when more than one arrows exist, there's a higher-order function
</source>
</source>
== Imperative versus declarative ==
<source lang="js">
// making a string URL friendly
// IMPERATIVE way
const string = "Restaurants in Hanalei";
const urlFriendly = "";
for (var i = 0; i < string.length; i++) {
  if (string[i] === " ") {
    urlFriendly += "-";
  } else {
    urlFriendly += string[i];
  }
}
console.log(urlFriendly); // "Restaurants-in-Hanalei"
// DECLARATIVE way
const string = "Restaurants in Hanalei";
const urlFriendly = string.replace(/ /g, "-");
console.log(urlFriendly);
</source>
Reference: [http://c2.com/cgi/wiki?DeclarativeProgramming Declarative Programming wiki -- more about d/p paradigm]
Declaring DOM example
<source lang="js">
// imperative approach
const target = document.getElementById("target");
const wrapper = document.createElement("div");
const headline = document.createElement("h1");
wrapper.id = "welcome";
headline.innerText = "Hello World";
wrapper.appendChild(headline);
target.appendChild(wrapper);
// declarative approach using a React component
const { render } = ReactDOM;
const Welcome = () => (
  <div id="welcome">
    <h1>Hello World</h1>
  </div>
);
render(<Welcome />, document.getElementById("target"));
</source>
== Functional concepts ==
core concepts: immutability, purity, data transformation, higher-order functions, and recursion
=== Immutability ===
data mutation
<source lang="js">
let color_lawn = {
  title: "lawn",
  color: "#00ff00",
  rating: 0
};
function rateColor(color, rating) {
  color.rating = rating;
  return color;
}
console.log(rateColor(color_lawn, 5).rating); // 5
console.log(color_lawn.rating); // 5
</source>
in JS, function arguments are references to the actual data; we can rewrite so it does not harm the original data
<source lang="js">
const rateColor = function(color, rating) {
  return Object.assign({}, color, { rating: rating }); // take a blank object, copy copy to that object, and overwrite rating on the copy
};
console.log(rateColor(color_lawn, 5).rating); // 5
console.log(color_lawn.rating); // 4
// use the spread operator to copy the color into a new object and then overwrite its rating:
// equivalent to
const rateColor = (color, rating) => ({
  ...color,
  rating
});
</source>
adding elements to an array
<source lang="js">
let list = [{ title: "Rad Red" }, { title: "Lawn" }, { title: "Party Pink" }];
const addColor = function(title, colors) {
  colors.push({ title: title });
  return colors;
};
console.log(addColor("Glam Green", list).length); // 4
console.log(list.length); // 4
// use Array.concat to keep immutable
const addColor = (title, array) => array.concat({ title });
console.log(addColor("Glam Green", list).length); // 4
console.log(list.length); // 3
// equivalent using spread operator
// copies the original list to a new array and then adds a new object containing the color's title to that copy.
const addColor = (title, list) => [...list, { title }];
</source>
=== Pure Functions ===
function that returns a value that is computed based on its argument; treats arguments as immutable data, so nothing else is changed about the application
e.g. impure function
<source lang="js">
const frederick = {
  name: "Frederick Douglass",
  canRead: false,
  canWrite: false
};
function selfEducate() {
  frederick.canRead = true;
  frederick.canWrite = true;
  return frederick;
}
selfEducate();
console.log(frederick);
// {name: "Frederick Douglass", canRead: true, canWrite: true}
// still the same result
const selfEducate = person => {
  person.canRead = true;
  person.canWrite = true;
  return person;
};
console.log(selfEducate(frederick));
console.log(frederick);
// {name: "Frederick Douglass", canRead: true, canWrite: true}
// {name: "Frederick Douglass", canRead: true, canWrite: true}
</source>
have this function take an argument (now pure)
<source lang="js">
const frederick = {
  name: "Frederick Douglass",
  canRead: false,
  canWrite: false
};
const selfEducate = person => ({
  ...person,
  canRead: true,
  canWrite: true
});
console.log(selfEducate(frederick));
console.log(frederick);
// {name: "Frederick Douglass", canRead: true, canWrite: true}
// {name: "Frederick Douglass", canRead: false, canWrite: false}
</source>