Created by Guido D'Orsi / @fughye
Guido D'Orsi
Retro games lover
Frontend web developer @ ImmobiliareLabs
How to improve our Javascript modules with a functional approach.
function Geocoder(input, output, button) {
var _this = this;
this.input = input;
this.output = output;
this.geocoder = new google.maps.Geocoder();
button.addEventListener('click', function () {
_this.geocodeAddress();
});
}
Geocoder.prototype.geocodeAddress = function () {
var _this = this;
this.geocoder.geocode({
address: this.input.value
}, function (results, status) {
_this.handleGeocodeResult(results, status);
});
};
Geocoder.prototype.handleGeocodeResult = function (results, status) {
var location = {},
components, i, l;
if (results && results.length > 0 && status == google.maps.GeocoderStatus.OK) {
components = results[0]['address_components'];
for(i = 0, l = addressComponents.length; i < l; i++){
switch(addressComponents[i].types[0]){
case 'administrative_area_level_2':
location.province = components[i].short_name;
break;
...
case 'street_number':
location.streetNumber = components[i].long_name;
break;
}
}
this.locationData = location;
this.showAddress();
} else {
alert('Insert a valid address');
}
};
Geocoder.prototype.showAddress = function () {
var formattedData = this.locationData.province + ', ' +
this.locationData.city + ', ' + this.locationData.route;
if(this.locationData.streetNumber){
formattedData += ', ' + this.locationData.streetNumber;
}
this.output.textContent = formattedData;
};
iNeedACallback(firstClass);
function iNeedArgs() {
return Array.prototype.slice.call(arguments, 1);
}
function firstClassSlice(array, from, to) {
return Array.prototype.slice.call(array, from, to);
}
function iNeedArgs() {
return firstClassSlice(arguments, 1);
}
“A pure function is a function that, given the same input, will always return the same output and does not have any observable side effect.”
//impure
var goodEnaugh = 6;
function doYouLikeThisTip(vote) {
return vote >= goodEnaugh && 'Yes' || 'No';
}
function doYouLikeThisTip(voto) { var goodEnaugh = 6; return voto >= goodEnaugh && 'Si' || 'No'; }var config = Object.freeze({ goodEnaugh: 6 }); function doYouLikeThisTip(v) { return vote >= config.goodEnaugh && 'Yes' || 'No'; }
Geocoder.prototype.showAddress = function () {
var formattedData = this.locationData.province + ', ' +
this.locationData.city + ', ' + this.locationData.route;
if(this.locationData.streetNumber){
formattedData += ', ' + this.locationData.streetNumber;
}
this.output.textContent = formattedData;
}
//Transform locationData in a formatted string
function formatAddress(locationData) {}
//Show the formatted string in the output element
function showAddress(output, formattedData) {}
function formatAddress(locationData) {
var formattedData = locationData.province + ', ' +
locationData.city + ', ' + locationData.route;
if(locationData.streetNumber){
formattedData += ', ' + locationData.streetNumber;
}
return formattedData;
}
function showAddress(output, formattedData) {
output.textContent = formattedData;
}
function showAddress(output, formattedData) {
return function() {
output.textContent = formattedData;
};
}
curry(function add(a, b) {
return a + b;
})
//Partial
var increment = add(1);
//Execution
increment(10);
//11
var curry = require('lodash/curry');
var join = curry(function (glue, array) {
return array && array.join(glue);
});
var joinWithComma = join(', ');
joinWithComma(['RM', 'Rome']);
//Rm, Rome
function join(glue, array) {
return array && array.join(glue);
};
var joinWithComma = join.bind(null, ', ');
joinWithComma(['RM', 'Rome']);
//Rm, Rome
function formatAddress(locationData) {
var formattedData = locationData.province + ', ' +
locationData.city + ', ' + locationData.route;
if(this.locationData.streetNumber){
formattedData += ', ' + locationData.streetNumber;
}
return formattedData;
}
function locationDataToArray(locationData){
return locationData && [
locationData.province,
locationData.city,
locationData.route,
locationData.streetNumber
] || [];
}
function formatAddress(locationData) {
return joinWithComma(
locationDataToArray(locationData)
);
}
var filter = curry(function (predicate, array) {
return array && array.filter(predicate);
});
function isTruthy(value) {
return !!value;
}
var filterInvalid = filter(isTruthy);
function formatAddress(locationData) {
return joinWithComma(
filterInvalid(
locationDataToArray(locationData)
)
);
}
function compose(f, g) {
return function(x) {
return f(g(x));
};
};
function formatAddress (locationData) { return joinWithComma( filterInvalid( locationDataToArray(locationData) ) ); }var compose = require('lodash/flowRight'); var formatAddress = compose( join(', '), filter(isTruthy), locationDataToArray );
Geocoder.prototype.handleGeocodeResult = function (results, status) {
var locationData = {},
addressComponents, i, l;
if (results && results.length > 0 && status == google.maps.GeocoderStatus.OK) {
addressComponents = results[0]['address_components'];
for(i = 0, l = addressComponents.length; i < l; i++){
switch(addressComponents[i].types[0]){
case 'administrative_area_level_2':
locationData.province = addressComponents[i].short_name;
break;
...
case 'street_number':
locationData.streetNumber = addressComponents[i].long_name;
break;
}
}
this.locationData = locationData;
this.showAddress();
} else {
alert('Insert a valid address');
}
};
function validGeocodeResponse(results, status) {
return status == google.maps.GeocoderStatus.OK && results;
}
var reduce = require('lodash/collection/reduce');
function transformAddressComponents(addressComponents) {
return addressComponents && reduce(addressComponents, function(res, component) {
switch(component.types[0]){
case 'administrative_area_level_2':
res.province = component.short_name;
break;
...
case 'street_number':
res.streetNumber = component.long_name;
break;
}
return res;
}, {}) || {};
}
var getProperty = curry(function (propName, obj) { return obj && obj[propName]; }); var first = getProperty(0);var formatGeocodeResponse = compose( formatAddress, transformAddressComponents, getProperty('address_components'), first, validGeocodeResponse );
var showAddress = curry(function(errorMessage, output, formattedData) {
if(formattedData) {
output.textContent = formattedData;
} else {
alert(errorMessage);
}
});
var geocode = curry(function (geocoder, output, address) {
geocoder.geocode({
address: address
}, compose(
showAddress('Insert a valid address', output),
formatGeocodeResponse
));
})
function manageAddressGeocoding(input, output, button){
var geocodeOnOutput = geocode(
new google.maps.Geocoder(),
output
);
button.addEventListener('click', function() {
geocodeOnOutput(input.value);
});
}