23
loading...
This website collects cookies to deliver better user experience
map(...)
or filter(...)
, each of which returns a new array, to which you can apply further calls. As a trivial (somewhat exaggerated!) example, let's see some code from my Mastering JavaScript Functional Programming book. We can start by defining some essentially nonsensical operations:const testOdd = x => x % 2 === 1;
const testUnderFifty = x => x < 50;
const duplicate = x => x + x;
const addThree = x => x + 3;
const myArray = [22, 9, 60, 24, 11, 63];
const a0 = myArray
.filter(testOdd)
.map(duplicate)
.filter(testUnderFifty)
.map(addThree);
// [ 21, 25 ]
.map(...)
and .filter(...)
operations return a new array, to which you can apply further operations. You could have done this in several lines as shown below, but (I hope) you'll agree that this isn't as clear. (A reader would wonder if x1
, x2
, and x3
would be used again, for example.) This is the alternative code:const x1 = myArray.filter(testOdd);
const x2 = x1.map(duplicate);
const x3 = x2.filter(testUnderFifty);
const a0 = x3.map(addThree);
// [ 21, 25 ]
$("#titlephoto")
.attr({
alt: "Street scene",
title: "Pune, India",
})
.css("background-color", "black")
.show();
const fakeTest = jest
.fn()
.mockReturnValueOnce(true)
.mockReturnValueOnce(false)
.mockReturnValue(undefined);
d3.select("svg")
.append("text")
.attr("font-size", "20px")
.attr("transform", "translate(100,0)")
.attr("x", 150)
.attr("y", 200)
.text("Sample Chart Title");
return this
at the end -- excepting, obviously, methods that need to return something else! This is certainly a solution, but we may think of something that needs less work, and proxy objects are a possibility.return undefined
statement had been added to functions or methods that don't otherwise return anything - so if your class has a method that may actually return undefined
, we're in trouble!makeChainable(...)
function will transform an object into a chainable alternative, all of whose methods (that don't return undefined
) will be returning a reference to the object itself.const makeChainable = (obj) =>
new Proxy(obj, {
get(target, property, receiver) { /* 1 */
return typeof target[property] === "function" /* 2 */
? (...args) => { /* 3 */
const result = target[property](...args); /* 4 */
return result === undefined ? receiver : result; /* 5 */
}
: target[property]; /* 6 */
}
});
class Mobster {
constructor(firstName, lastName, nickname) {
this.firstName = firstName;
this.lastName = lastName;
this.nickname = nickname;
}
setFirstName(newFirst) {
this.firstName = newFirst;
}
setLastName(newLast) {
this.lastName = newLast;
}
setNickname(newNickname) {
this.nickname = newNickname;
}
getFullName() {
return `${this.firstName} "${this.nickname}" ${this.lastName}`;
}
}
return this
, so you cannot chain methods. Certainly, we could rewrite the class by adding some lines as follows... but we'll look for a better, functional way of doing this.class Mobster {
constructor(...) { ... }
setFirstName(newFirst) {
this.firstName = newFirst;
return this; /* added */
}
setLastName(newLast) {
this.lastName = newLast;
return this; /* added */
}
setNickname(newNickname) {
this.nickname = newNickname;
return this; /* added */
}
getFullName() { ... }
}
const makeMobster = (...args) => makeChainable(new Mobster(...args));
const gangster = makeMobster("Alphonse", "Capone", "Al");
console.log(gangster.getFullName());
// Alphonse "Al" Capone
console.log(
gangster
.setFirstName("Benjamin")
.setLastName("Siegel")
.setNickname("Bugsy")
.getFullName()
);
// Benjamin "Bugsy" Siegel