javascript
patterns
2017-04-26
literals
pojo
{
year: 1981,
make: "Toyota",
model: "Tercel",
description: "Red with white fenders"
}
to create an object shaped like
const myFirstCar = {
year: 1981,
make: "Toyota",
model: "Tercel",
description: "Red with white fenders"
};
we literally just:
what about methods?
🙈 if you're into that sort of thing
const myFirstCar = {
year: 1981,
make: "Toyota",
model: "Tercel",
description: "Red with white fenders",
tryToStart() {
return Math.random() < .3;
}
}
"methods"
this might seem basic
but the ability to create objects literally anywhere without first having to define a class is fundamentally different
🤔
JavaScript
literally more object oriented?
🤔
vs "class" oriented?
factories
{
year: 1981,
make: "Toyota",
model: "Tercel",
description: "Red with white fenders"
}
to create a bunch of objects shaped like
function Car(year, make, model, description) {
this.year = year;
this.make = make;
this.model = model;
this.description = description;
}
we can
const myFirstCar = new Car(
1981,
"Toyota",
"Tercel",
"Red with white fenders"
);
const mySecondCar = new Car(
1991,
"Nissan"
"Sentra"
);
and then
constructor function
or
class Car {
constructor(year, make, model, description) {
this.year = year;
this.make = make;
this.model = model;
this.description = description;
}
}
we can
const myFirstCar = new Car(
1981,
"Toyota",
"Tercel",
"Red with white fenders"
);
const mySecondCar = new Car(
1991,
"Nissan"
"Sentra"
);
and then
"class"
or
In JavaScript, we can literally create a new object anywhere.
- literally a few slides ago
In JavaScript, any function can return a new object. When it’s not a constructor function or class, it’s called a factory function
- someone on the internet
const createCar = (year, make, model, description) =>
({ year, make, model, description });
factory
const myFirstCar = createCar(
1981,
"Toyota",
"Tercel",
"Red with white fenders"
);
const mySecondCar = createCar(
1991,
"Nissan"
"Sentra"
);
and then
class Car {
constructor(year, make, model, description) {
this.year = year;
this.make = make;
this.model = model;
this.description = description;
}
}
"class"
function Car(year, make, model, description) {
this.year = year;
this.make = make;
this.model = model;
this.description = description;
}
constructor function
const createCar = (year, make, model, description) =>
({ year, make, model, description });
"factory"
compare
object composition
a way to combine simple objects or data types into more complex ones.
- wikipedia
const turtle = {animal: "turtle"};
eg: take objects shaped like
and create a new object that looks like
{
age: 16,
isMutant: true,
job: "ninja",
animal: "turtle"
}
const mutant = {isMutant: true};
const ninja = {job: "ninja"};
const teenage = {age: 16};
...
const tmnt = {
...teenage,
...mutant,
...ninja,
...turtle
};
💥
const tmnt = Object.assign(
{},
teenage,
mutant,
ninja,
turtle
);
☝️ Everything but IE (MS Edge+)
and easy to polyfill
mixins
classeswhich offer functionality that can be easily inherited by a sub-classor group of sub-classesfor the purpose of function re-use.
- Addy
emphasis mine
factory composition
- me
const createTheNextTMNT = () => ({
...createRandomAgeBracket(),
...createRandomGeneticAlteration(),
...createRandomProfession(),
...createRandomAnimal()
});
hollywood idea generator
decorators
allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same
class
- wikipedia
emphasis mine
append data or behavior to an object
- JAT
const betterThanBefore = {
...obj,
bacon: true
};
one-off decoration
const makeBetterThanBefore = (obj) =>
({ ...obj, bacon: true });
decoration factory
inheritance
⚠️ opinions
prefer composition over inheritance
⚠️ opinion alert
when possible
prefer shallow inheritance
⚠️ opinion alert
when composition not feasible
velocity
why?
many reasons that all basically boil down to:
🏃💨
class Button extends React.Component {}
class Widget extends HTMLElement {}
"classes" aka prototypes
closures
Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.
- MDN
closures
NEVER FORGET
🇺🇸
currying exemplifies a closure
👇
const createSecretContainer = (secret) => () => secret;
- a function which accepts an argument and creates & returns a function
- the created "inner" function has access to the "outer" function's scope
outer fn
const mySecretContainer = createSecretContainer(
"my password is 1234"
);
- `mySecretContainer` is the returned, inner function
- `mySecretContainer` still "remembers" the `secret` defined in its original outer scope
inner fn
counter: a closure demo
const counter = (number=0) => ({
inc: () => ++number,
dec: () => --number,
val: () => number
});
iife
Immediately Invoked Function Expression: a JavaScript function that runs as soon as it is defined
- MDN
useful for encapsulating scope
aka privacy
(() => {
var n = 1;
console.log(n);
})();
console.log(typeof n);
example
a foundational concept, but generally not authored directly nowadays
{
const n = 1;
console.log(n);
}
console.log(typeof n);
- privacy via block-scoped const & let
- privacy via modules
module pattern
encapsulating functionality using
IIFE + closure
const Game = (() => {
let p1 = 0;
let p2 = 0;
return {
p1Scored(n=0) {
p1+=n;
},
p2Scored(n=0) {
p2+=n;
},
tally() {
return [p1, p2];
},
reset() {
p1 = p2 = 0;
return [p1, p2];
}
}
})();
example
Game.p1Scored(2);
Game.p2Scored(3);
Game.p1Scored(2);
Game.tally();
Game.reset();
- create an IIFE to encapsulate scope
- define private variables
- return an object containing functions which "remember" the variables `p1` and `p2`
- `Game` becomes the returned object
instead: cjs es6 modules 👉
another foundational concept, but generally not authored directly nowadays
es6 modules
let p1 = 0;
let p2 = 0;
export const p1Scored = (n=0) => {
p1+=n
};
export const p2Scored = (n=0) => {
p2+=n;
}
export const tally = () => [p1, p2];
export const reset = () => {
p1 = p2 = 0;
return [p1, p2];
}
example
import * as Game from './Game.js';
Game.tally();
Game.p1Scored(2);
Game.p2Scored(3);
Game.p1Scored(2);
Game.tally();
Game.reset();
Game.p1Scored(2);
import {
tally,
p2Scored
} from './Game.js';
p2Scored(5);
tally();
import './file1.js';
import './file2.js';
./Game.js
./app.js
./file1.js
./file2.js
es6 modules:
like importing an IIFE module
facade
a convenient higher-level interface to a larger body of code, hiding its true underlying complexity
- Addy
modules
dude, just use
import handleComplexThingA from './a.js';
import handleComplexThingB from './b.js';
import handleComplexThingC from './c.js';
const facade = ({condition, ...data}) => {
if(condition==="a") {
return handleComplexThingA(data);
}
if(condition==="b") {
return handleComplexThingB(data);
}
if(condition==="c") {
return handleComplexThingB(data);
}
return null;
}
export default facade;
./index.js
looping
javascript patterns for dealing with lists of things
which loop type?
why are you looping?
async
asynchronous I/O, or non-blocking I/O is a form of input/output processing that permits other processing to continue before the transmission has finished
async patterns
- events
- callbacks
- promises
- async/await
- observables (coming?)
end 👏
JavaScript Patterns
By Jared Anderson
JavaScript Patterns
- 2,252