composition in javascript
TRANSCRIPT
I'm Josh Mock.
I'm @joshmock on all of the things.
Except email, that's [email protected].
So original, right?
How do I compose things?
Find repeated patterns or duplications in your code and refactor them into reusable parts.
A simple examplevar obj1 = {
message: 'hello world!',
sayHi: function () {
alert(this.message);
}
};
var obj2 = {
message: 'hey!',
sayHi: function () {
alert(this.message);
}
};
obj1.sayHi(); // 'hello world!'
obj2.sayHi(); // 'hey!'
A simple examplevar obj1 = { message: 'hello world!' };var obj2 = { message: 'hey!' };
var alerter = { sayHi: function () { alert(this.message); }};
obj1 = _.extend(obj1, alerter);obj2 = _.extend(obj2, alerter);
obj1.sayHi(); // 'hello world!'obj2.sayHi(); // 'hey!'
● Maximize code reuse
● Use objects without classes
● Avoid traps of single-parent inheritance
Mixins
Underscore.js_.each(array, function) : Loop over each item in an array
_.map(array, function) : Reformat each item in an array
_.filter(array, function) : Make a new array containing only items that pass a test
_.reduce(array, function, start) : Calculate a single value from an array of items
Underscore.js_.chain(myArray)
.map(/* reformat items */)
.filter(/* pull out items you don't need */)
.reduce(/* crunch down to a single value */)
.value();
myArray
.map(/* reformat items */)
.filter(/* pull out items you don't need */)
.reduce(/* crunch down to a single value */)
You can do this in plain JS too
mapped = map(..., my_array)
filtered = filter(..., mapped)
final_val = reduce(..., filtered)
And in Python
var myList = [
{ count: 17 },
{ count: 22 },
{ count: 3 },
{ count: 18 }
];
var sum = 0;
for (var i = 0; i < myList.length; i++) {
sum += myList[i].count;
}
Function reuse
Function reusefunction getCount (value) {
return value.count;
}
function noOdds (value) {
return value % 2 === 0;
}
function add (value1, value2) {
return value1 + value2;
}
Function reusevar myList = [
{ count: 17 },
{ count: 22 },
{ count: 3 },
{ count: 18 }
];
var sum = _.chain(myList)
.map(getCount)
.filter(noOdds)
.reduce(add)
.value();
each / map / filter / reducefunction getForms (data) {
var forms = data.aggregate.all[window.location.protocol + '//' + window.location.host];
var formsOut = [];
var url = window.location.toString();
var formsToExclude = [];
for (var key in data.aggregate.exclude) {
if (new RegExp('^' + key + '$').test(url)) {
formsToExclude = formsToExclude.concat(data.aggregate.exclude[key]);
}
}
var filteredForms = [];
for (value in forms) {
if (formsToExclude.indexOf(value) === -1) {
filteredForms.push(value);
}
}
for (key in data.aggregate.include) {
if (new RegExp('^' + key + '$').test(url)) {
forms = forms.concat(data.aggregate.include[key]);
}
}
return formsOut;
}
each / map / filter / reducefunction getForms (data) {
var forms = data.aggregate.all[window.location.protocol + '//' + window.location.host];
var url = window.location.toString();
var formsToExclude = [];
_.each(data.aggregate.exclude, function (val, key) {
if (new RegExp('^' + key + '$').test(url)) {
formsToExclude = formsToExclude.concat(val);
}
});
forms = _.filter(forms, function (val) {
return formsToExclude.indexOf(val) === -1;
});
_.each(data.aggregate.include, function (val, key) {
if (new RegExp('^' + key + '$').test(url)) {
forms = forms.concat(val);
}
});
return forms || [];
}
each / map / filter / reduce
● Small, single-purpose functions
● Maintainable
● Reusable
● Easy to test
● Universally understandable
Web components● HTML is perfectly composable:
<form> <input type="text"> <button>click me</button></form>
● Custom elements = infinite composition possibilities!
"This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface."
- Doug McIlroy
The Unix Philosophy
A Node.js API to read in data, act on it in chunks, then then write out to a new stream.
Node streams
Node streamsgulp.task('scripts', function() { return gulp.src('js/*.js') .pipe(concat('all.js')) .pipe(gulp.dest('dist')) .pipe(rename('all.min.js')) .pipe(uglify()) .pipe(gulp.dest('dist'));});
Microservices
"...an approach to developing a single application as a suite of small services, each running in its own process."