I trying to wrap my head around functional programming in js.
I understand add(3)(5) would be:
function add(x) {
return function(y) {
return x + y;
};
}
How would I change this function so add(3)(5)(7)(8) returns 23 or add(1)(2)(3) returns 6?
you can do something like this.
function add(x) {
return function(y) {
if (y) {
return add(x+y);
}
return x;
};
}
Here, you can call as many times as you want.
add(4)();
add(4)(5)(9)();
add(1)(2)(3)....(n)();
Example link
Without modifying your definition for add, you would need to chain the calls to add to be (add(add(add(3)(5))(7)))(8).
to clarify, this expression breaks down to:
add(3) //returns a function that adds 3
add(3)(5) //returns 8
add(add(3)(5)) // returns a function that adds 8
(add(add(3)(5)))(7) // returns 15
add ((add(add(3)(5)))(7)) //returns function that adds 15
(add(add(add(3)(5))(7)))(8) //returns 23
Breaking it down even further as #zerkms mentioned (and assigning our function definitions to variables) we can see how the chaining of add works:
var add3 = add(3) //returns a function that adds 3
add3(5) //returns 8
var add8 = add(add3(5)) // returns a function that adds 8
add8(7) // returns 15
var add15 = add(add8(7)) //returns function that adds 15
add15(8) //returns 23
By chaining, we are adding on to the result of the previous call to add.
Meaning that if add(3) returns a function that adds 3 and then you add 5 to that number than you can pass that value, 8, into another call to add to make another function that adds 8 to it's argument.
How about:
function add(x) {
return function(y) {
return y == 0 ?
x + y :
add(x + y);
};
}
add(3)(5)(7)(8)(0) // ==> 23
add(1)(2)(3)(0) // ==> 6
The trick here is that it knows when to return a function or the answer by the value of the argument. The "stop" value could be anything really but in my example it's 0 which triggers the answer.
TL;DR
A number cannot be invoked as a function. So use the composite pattern and return a function that has an accumulated result at each iteration. Here is one way to implement add from a factory with tests and example usage: http://jsbin.com/qaqiqu/edit?js,console
Details:
var factory = (function (){
"use strict";
var reduceFactory = function (options) {
var defaultReduce = function (x, y) { return x + y; },//add
noLog = function () {};
function store(x) {
if (options && options.log) {
options.log(x, options.acc, options);
}
options.acc = options.f(options.acc, x);
store.result = options.acc;
return store;
}
//default options
options = typeof options !== 'undefined' ? options : {};
options.f = typeof options.f !== 'undefined' ? options.f : defaultReduce;
options.acc = typeof options.acc !== 'undefined' ? options.acc : 0;
options.log = typeof options.log !== 'undefined' ? options.log : noLog;
return store;
};
return reduceFactory;
}());
//example usage
(function (f) {
var add = f(),
add1 = f(),
add2 = f(),
add3 = f(),
add4 = f(),
clear = function(f) {
return f(-f.result);
};
//how to use a single function
console.log('add(3)(5)(7)(8).result = ' + add(3)(5)(7)(8).result);
clear(add);
console.log('add(1)(2)(3).result = ' + add(1)(2)(3).result);
//how to use factory functions
console.log('add1(3)(5)(7)(8).result = ' + add1(3)(5)(7)(8).result);
console.log('add2(1)(2)(3).result = ' + add2(1)(2)(3).result);
//factory functions can continue to grow as needed
add3(3)(5);
add3(7)(8);
console.log('add3(3)(5); add3(7)(8); add3.result = ' + add3.result);
add4(3);
add4(5);
add4(7);
add4(8);
console.log('add4(3); add4(5); add4(7); add4(8); add4.result = ' + add4.result);
}(factory));
When the add function finally returns a number, then the number cannot be invoked as a function. The normal way around this is to specify how many arguments are required before a number will finally be returned, as suggested in other answers. Some answers suggested a function terminator (0, undefined) as a novel approach, but from the comments, the OP is
"looking for a solution without the need to end with () or (0)"
Using the composite pattern, we can return a function that can also be used as a number by giving it a result property. That way we can keep accumulating the result with an increasing number of function calls. We can use a factory function to create instances of add if we need to do separate additions. Alternatively we can reset a single instance of add to zero when a separate addition is needed.
I have also written a custom set of test assertions with the following passing test cases:
var testCases = [
{arguments: [0], expectedResult: 0},
{arguments: [5, 0, 0, 5, 10, -1], expectedResult: 19},
{arguments: [1], expectedResult: 1},
{arguments: [1, 2], expectedResult: 3},
{arguments: [1, 2, 3], expectedResult: 6},
{arguments: [3, 5, 7, 8], expectedResult: 23},
{arguments: [3, 4], expectedResult: 7},//{acc: 1000}
{arguments: [1, 2], expectedResult: 1003, factoryOptions: {acc: 1000}},
//example tests with logging to debug
//{arguments: [1, 2], expectedResult: 3, factoryOptions: {f: add, log: addLog}},
//{arguments: [3, 4], expectedResult: -7, factoryOptions: {f: sub, log: subLog}},
{arguments: [3, 4], expectedResult: -7, factoryOptions: {f: sub}}
]
I have used inversion of control and made the reduce function an optional parameter to the factory. For example, instead of using add you could use sub (i.e. x - y) as demonstrated in the test cases.
Simply put, the title and the body of the question are about different things.
Firstly, functional programming is not about n-ary functions. You can construct the examples shown before, for instance with recursion (to maintain immutability); however, you then sacrifice the totality of the function. For instance, the 0 terminated functions could crash at runtime if you had external parameters that you didn't validate to be as non-zero.
The solution that would enable totality then either accepts non-zero integers (JavaScript only has 'number' type), and gets called with zero to get the value.
Alternatively, a monad could allow you to combine the properties of a number while returning a function that could be bound further. (But then you wouldn't end up with a pure 'number' but rather a custom 'add' monad. Useful, but has to be implemented.)
Otherwise, the add function could just be a sum of a list. Then it can have from 1 to N elements for computation, it just wouldn't be it's arguments.
Now, as to why variable arity is not very functional, the reasons are pretty fundamental. For one, if you had a function f(a)(b)(c)(d)...(n) what is it's type? Without types, you lose many core aspects of the field. If it always returns type of itself (which is possible, shown by the recursive example) then it's useless as it cannot actually generate side effects. Now to make it useful, while maintaining purity, we cannot just constraint the domain (i.e.) with zero, because then we're 'lying', since zero is a part of valid inputs; the result is just not going to be of the same type as the function. Hence, if we we're to make a wrapper function that validated all inputs as non-0 (and ignored the 0's) and after the last member called 0, we're doing the exact same thing as discussed before, simply in a different manner.
For instance, we could have a 'Maybe number' as an input, and when it's not a number, the result gets returned (thus totality but functionality). Or we could have a list, and after the list is over, we're once again 'detecting' a change (in a different place, i.e, seeing if the size of the vector has been exhausted; or if there's no more members in a list.)
Either way this is implemented, it does the same thing. Difference is in usability, number of bugs, readability, maintainability, accepted data types, language, or perspective.
A note on why is this all so complicated: supplying an argument on its own is the exact same thing as calling the function. Thus f(a)(b)(c)(d) has 4 applications, with none of them being 'the last one', they are ordered, but there's no implicit finite boundary. The creation of which again loops back to my previous statement of how this is the same exact problem with different implementations.
All of the solutions follow this pattern in one way or another. Chaining the binary add operation results in a very similar data flow to the recursion; however, the boundary is hard coded. The recursion is similar to the OOP style where the sum is accumulated and can be retrieved at any point. Which is similar to the 'Add' Monad which would contain both the addition function together with the current state, and so essentially the 'next' user after the add function would discard the function and keep the state.
I think the simplest solution in terms of the given problem is:
[1,2,3,4,5].reduce( function add(sum, x) {sum+x}, 0)
Related
TypeScript function chaining, but I want to programmatically chain them.
Example class: chain.ts
class MyChain {
value: number = 0;
constructor() {
this.value = 0;
}
sum(args: number[]) {
this.value = args.reduce((s, c) => s + c, 0);
return this;
}
add(v: number) {
this.value = this.value + v;
return this;
}
subtract(v: number) {
this.value = this.value - v;
return this;
}
}
const mc = new MyChain();
console.log(mc.sum([1, 2, 3, 4]).subtract(5).value);
I see the number 5 on the console.
Now, I'm still fairly new to JavaScript and TypeScript, so I figured out that the function within this class is actually an element of an array of the instance of the class. Hence, I can do this:
console.log(mc["sum"]([1, 2, 3, 4]).value);
This indeed returns the number 10.
Now, I'm confused as to how I'd chain this programmatically. For example (this is obviously not what I would want to do anyway and shows my boneheaded lack of understanding of JavaScript:
console.log(mc["sum"]([1, 2, 3, 4]).mc["subtract"](5).value);
Error:
Property 'mc' does not exist on type 'MyChain'.ts(2339)
Okay, in all honesty, I kind of intuitively knew that wasn't going to work. However, thinking about it, how would I go about accessing the elements of a multidimensional array in just about any reasonable language?
console.log(mc["sum"]([1, 2, 3, 4])["subtract"](5).value);
Bingo. This does the trick. But, this isn't really the solution I need. What I need is something like this:
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4] },
{ action: "subtract", operand: 5 },
];
And, to start, I'd like to try this:
console.log(mc[chainObj[0].action](chainObj[0].operand).value);
And consequently, generating a mechanism that would ultimately build something like this:
console.log(
mc[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](
chainObj[1].operand
).value
);
Hence, it seems to me that what I want is some way to generate this:
[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](chainObj[1].operand)
from this, with my chain object having one or many action/operand object sets:
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4] },
{ action: "subtract", operand: 5 },
];
Now, this is where my brain more or less shuts down. I am thinking that I need to generate a chain of string values, but they'll just be strings and won't really work as array indexes into the function as I want.
Why do I want to do this? Ultimately, I want to build a complex Yup schema object from a JSON object. I found this excellent post, but my core issue is I don't really understand how this code works.
At this point, I am able to parse out the way Vijay was able to solve his issue and mimic it, in a way. Here's working code for my example:
const mc = new MyChain();
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
let myChain = {};
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
console.log("myChain is", myChain["value"]);
Results in: myChain is 10
You're probably asking yourself, "What's your problem Dan?. You seem to have a solution in hand now." Yes, I guess I do, but I don't understand it. I'm basically copying and pasting code, marginally understanding it, and making changes that make it work.
My basic issue is I don't understand how this line of code works: myChain = mc[o.action](o.operand);
I get the general gist that it's calling the function based on the action and providing the data to the function via the operand. I'm a copy and paste code monkey. I want to be more than a monkey. Maybe a baboon or even ape. Hence, I want to understand what I've done. What doesn't make sense to me is how it's chaining it.
I thought maybe the secret was in the forEach function, but that doesn't seem to be it. Here is a simple test:
let p = 0;
const x = [1, 2, 3, 4];
x.forEach((y) => {
p = y;
});
console.log("p is", p); p is 4
What is the secret JavaScript magic that is happening under the hood that makes the myChain = mc[o.action](o.operand); code actually chain my functions together rather than simply work one and the work the other. I'm just not seeing it.
Let's start from the first misunderstanding I can find:
Now, I'm still fairly new to JavaScript and TypeScript, so I figured out that the function within this class is actually an element of an array of the instance of the class.
This is not the case. Square brackets in Javascript are used for all property lookups, not just array indexing. x.foo is actually equivalent to x["foo"], and the same syntax works for arrays since arrays are just objects. Classes in Javascript are just objects that have a prototype property, which is itself an object. It contains a list of default attributes, and if you instantiate a class and look up a property that isn't in the object, it'll search for it in the prototype. So, looking at the code:
mc["sum"]([1, 2, 3])
It searches for a "sum" property in mc, and can't find any since you haven't defined one, so it searches in the prototype of MyChain, and finds the mc method. Thus, mc["sum"] is the sum method of mc. Now, this code:
console.log(mc["sum"]([1, 2, 3, 4]).mc["subtract"](5).value);
doesn't work, and it looks very off for a reason. mc["sum"]([1, 2, 3, 4]) returns mc, so why would you have to access the mc property (not that the mc property even exists)? That's why your second example, the one that calls subtract directly, works:
console.log(mc["sum"]([1, 2, 3, 4])["subtract"](5).value);
Now, let's look at the working code:
const mc = new MyChain();
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
let myChain = {};
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
console.log("myChain is", myChain["value"]);
You actually don't need a lot of this code. It can be simplified down to:
const mc = new MyChain();
interface IChainObject {
action: keyof MyChain;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
chainObj.forEach((o) => {
// bypass typescript type checking with cast
(mc[o.action] as Function)(o.operand);
});
console.log("myChain is", mc.value);
Essentially, the forEach loops through the elements in chainObj in order. The element's value is stored in the variable o. mc[o.action] takes the method name stored in o.action, and accesses it using square brackets. This is basically looking up the method. Then, the method is called with (o.operand) (in Javascript functions are just values, and you can call any value like a function, but if it's not a function it'll error). mc then modifies itself, and you move on to the next loop. If we insert a debugger statement in the function then break on the first loop, we can inspect the variables:
As you can see, the value starts off at 0, o.action is "sum", and mc[o.action] is the sum method. We can then call the sum method with o.operand, which adds the elements up and sets the value to 15. Then, in the second loop:
mc[o.action] is the subtract method, and we call it with o.operand, which is 5, lowering the value to 10.
Most things in Javascript, like classes are basically just objects.1
What that means is that attributes, or in this case - functions, can be accessed via the dot notation or bracket notation.
Lets look at an example that might assist the explanation:
class MyClass {
myFunction(x) {
console.log(x);
}
}
const x = new MyClass();
// attribute accessed via the dot notation
x.myFunction("Hello World!");
// attribute accessed via the bracket notation and a string
x['myFunction']("Hello World, again!");
// attribute accessed via a variable that is a string
const functionName = 'myFunction';
x[functionName]("Well uh, Hello World again?");
// attribute accessed via a variable that is a string, and passing in an argument
const argument = "This is " + "an argument";
x[functionName](argument);
To illustrate the point further:
class MyClass {
myFunction(x) {
console.log(x);
}
}
const x = new MyClass();
console.log(x.myFunction) // returns a function
console.log(x["myFunction"]) // returns a function
// executing the function
x.myFunction("Method One");
x["myFunction"]("Method Two")
We can see that the returned function can be called.
So let's get back to your example
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
o.action is the function name
o.operand is the argument
Therefore, what is roughly translates to is:
chainObj.forEach((o) => {
myChain = mc[functionName](arugment);
});
just like our previous examples.
1 "classes are basically just objects"
There are so many pieces of this; I'm just going to focus on "what's the secret that makes the forEach() code work?"
The "secret" is that instances of MyChain have a property named value that gets updated after each method is called. The code with forEach() is not really chaining calls together; it just operates on the original MyChain variable named mc each time.
Since all the methods of MyChain that update this.value also return this, it happens not to matter whether you really chain calls (operate on the return value of each method call):
const chaining = new MyChain();
console.log(chaining.add(3).subtract(1).value); // 2
or if you just call methods on the original object in succession:
const notChaining = new MyChain();
notChaining.add(3);
notChaining.subtract(1);
console.log(notChaining.value) // 2
If you want there to be a difference between those, you can show it by making two versions of MyChain; one that only works via chaining, and one that only works in succession.
The following requires chaining because it never updates the original object and method calls return new objects with the results of the method call:
class RealChain {
constructor(public value: number = 0) { }
sum(args: number[]) {
return new RealChain(args.reduce((s, c) => s + c, 0));
}
add(v: number) {
return new RealChain(this.value + v);
}
subtract(v: number) {
return new RealChain(this.value - v);
}
}
const realChaining = new RealChain();
console.log(realChaining.add(3).subtract(1).value); // 2
const notRealChaining = new RealChain();
notRealChaining.add(3);
notRealChaining.subtract(1);
console.log(notRealChaining.value) // 0
and the following prohibits chaining, because it only updates the original object and its methods don't return anything:
class NotChain {
value: number = 0;
constructor() {
this.value = 0;
}
sum(args: number[]) {
this.value = args.reduce((s, c) => s + c, 0);
}
add(v: number) {
this.value = this.value + v;
}
subtract(v: number) {
this.value = this.value - v;
}
}
const realNotChaining = new NotChain();
realNotChaining.add(3);
realNotChaining.subtract(1);
console.log(realNotChaining.value) // 2
const badNotChaining = new NotChain();
console.log(badNotChaining.add(3).subtract(1).value); // error!
// badNotChaining.add(3) is undefined so you can't call subtract() on it
The code with forEach() would only work with NotChain instances and not with RealChain instances.
If you want a programmatic loop-like thing that actually works with chaining and not calling methods on an original object, you should probably use reduce() instead of forEach():
const realChainReduced = chainObj.reduce(
(mc, o) => mc[o.action](o.operand),
new RealChain() // or MyChain, doesn't matter
);
console.log("realChainReduced is", realChainReduced.value); // 10
Note that I didn't cover any of the other parts, including TypeScript specifics (the typings used here give some compiler errors), so be warned.
Playground link to code
I find the named parameters feature in C# quite useful in some cases.
calculateBMI(70, height: 175);
What can I use if I want this in JavaScript?
What I don’t want is this:
myFunction({ param1: 70, param2: 175 });
function myFunction(params){
// Check if params is an object
// Check if the parameters I need are non-null
// Blah blah
}
That approach I’ve already used. Is there another way?
I’m okay using any library to do this.
ES2015 and later
In ES2015, parameter destructuring can be used to simulate named parameters. It would require the caller to pass an object, but you can avoid all of the checks inside the function if you also use default parameters:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...function body...
}
// Or with defaults,
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
// ...function body...
}
ES5
There is a way to come close to what you want, but it is based on the output of Function.prototype.toString [ES5], which is implementation dependent to some degree, so it might not be cross-browser compatible.
The idea is to parse the parameter names from the string representation of the function so that you can associate the properties of an object with the corresponding parameter.
A function call could then look like
func(a, b, {someArg: ..., someOtherArg: ...});
where a and b are positional arguments and the last argument is an object with named arguments.
For example:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,\s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === 'object') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
Which you would use as:
var foo = parameterfy(function(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
DEMO
There are some drawbacks to this approach (you have been warned!):
If the last argument is an object, it is treated as a "named argument objects"
You will always get as many arguments as you defined in the function, but some of them might have the value undefined (that's different from having no value at all). That means you cannot use arguments.length to test how many arguments have been passed.
Instead of having a function creating the wrapper, you could also have a function which accepts a function and various values as arguments, such as
call(func, a, b, {posArg: ... });
or even extend Function.prototype so that you could do:
foo.execute(a, b, {posArg: ...});
No - the object approach is JavaScript's answer to this. There is no problem with this provided your function expects an object rather than separate params.
Lots of people say to just use the "Pass an object" trick so that you have named parameters.
/**
* My Function
*
* #param {Object} arg1 Named arguments
*/
function myFunc(arg1) { }
myFunc({ param1 : 70, param2 : 175});
And that works great, except... when it comes to most IDEs out there, a lot of us developers rely on type / argument hints within our IDE. I personally use PhpStorm (along with other JetBrains IDEs, like PyCharm for Python and AppCode for Objective-C).
And the biggest problem with using the "Pass an object" trick is that when you are calling the function, the IDE gives you a single type hint and that's it... How are we supposed to know what parameters and types should go into the arg1 object?
So... the "Pass an object" trick doesn't work for me... It actually causes more headaches with having to look at each function's docblock before I know what parameters the function expects.... Sure, it's great for when you are maintaining existing code, but it's horrible for writing new code.
Well, this is the technique I use... Now, there may be some issues with it, and some developers may tell me I'm doing it wrong, and I have an open mind when it comes to these things... I am always willing to look at better ways of accomplishing a task... So, if there is an issue with this technique, then comments are welcome.
/**
* My Function
*
* #param {string} arg1 Argument 1
* #param {string} arg2 Argument 2
*/
function myFunc(arg1, arg2) { }
var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');
This way, I have the best of both worlds. New code is easy to write as my IDE gives me all the proper argument hints. And, while maintaining code later on, I can see at a glance, not only the value passed to the function, but also the name of the argument. The only overhead I see is declaring your argument names as local variables to keep from polluting the global namespace. Sure, it's a bit of extra typing, but it's trivial compared to the time it takes to look up docblocks while writing new code or maintaining existing code.
Update - 2022
JavaScript now has the ability to have something close to named parameters using object destructuring available in ES6. Most newer browsers can use this feature See browser support
This is how it works:
// Define your function like this
function myFunc({arg1, arg2, arg3}) {
// Function body
}
// Call your function like this
myFunc({arg1: "value1", arg2: "value2", arg3: "value3"})
// You can also have default values for arguments
function myFunc2({firstName, lastName, age = 21}) {
// Function body
}
// And you can call it with or without an "age" argument
myFunc({firstName: "John", lastName: "Doe"}) // Age will be 21
myFunc({firstName: "Jane", lastName: "Doe", age: 22})
The best part is that most IDE's now support this syntax and you get good argument hint support
TypeScript
For those of you using TypeScript, you can do the same thing using this syntax
function myFunc(
{firstName, lastName, age = 21}:
{firstName: string, lastName: string, age?: number}
) {
// Function body
}
OR, using an interface
interface Params {
firstName: string
lastName: string
age?: number
}
function myFunc({firstName, lastName, age = 21}: Params) {
// Function body
}
If you want to make it clear what each of the parameters are, rather than just calling
someFunction(70, 115);
do the following:
var width = 70, height = 115;
someFunction(width, height);
Sure, it's an extra line of code, but it wins on readability.
Another way would be to use attributes of a suitable object, e.g. like so:
function plus(a,b) { return a+b; };
Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}},
b: function(y) { return { a: function(x) { return plus(x,y) }}}};
sum = Plus.a(3).b(5);
Of course for this made up example it is somewhat meaningless. But in cases where the function looks like
do_something(some_connection_handle, some_context_parameter, some_value)
it might be more useful. It also could be combined with "parameterfy" idea to create such an object out of an existing function in a generic way. That is for each parameter it would create a member that can evaluate to a partial evaluated version of the function.
This idea is of course related to Schönfinkeling aka Currying.
Calling function f with named parameters passed as the object
o = {height: 1, width: 5, ...}
is basically calling its composition f(...g(o)) where I am using the spread syntax and g is a "binding" map connecting the object values with their parameter positions.
The binding map is precisely the missing ingredient, that can be represented by the array of its keys:
// map 'height' to the first and 'width' to the second param
binding = ['height', 'width']
// take binding and arg object and return aray of args
withNamed = (bnd, o) => bnd.map(param => o[param])
// call f with named args via binding
f(...withNamed(binding, {hight: 1, width: 5}))
Note the three decoupled ingredients: the function, the object with named arguments and the binding. This decoupling allows for a lot of flexibility to use this construct, where the binding can be arbitrarily customized in function's definition and arbitrarily extended at the function call time.
For instance, you may want to abbreviate height and width as h and w inside your function's definition, to make it shorter and cleaner, while you still want to call it with full names for clarity:
// use short params
f = (h, w) => ...
// modify f to be called with named args
ff = o => f(...withNamed(['height', 'width'], o))
// now call with real more descriptive names
ff({height: 1, width: 5})
This flexibility is also more useful for functional programming, where functions can be arbitrarily transformed with their original param names getting lost.
There is another way. If you're passing an object by reference, that object's properties will appear in the function's local scope. I know this works for Safari (haven't checked other browsers) and I don't know if this feature has a name, but the below example illustrates its use.
Although in practice I don't think that this offers any functional value beyond the technique you're already using, it's a little cleaner semantically. And it still requires passing a object reference or an object literal.
function sum({ a:a, b:b}) {
console.log(a+'+'+b);
if(a==undefined) a=0;
if(b==undefined) b=0;
return (a+b);
}
// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));
// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));
Coming from Python this bugged me. I wrote a simple wrapper/Proxy for node that will accept both positional and keyword objects.
https://github.com/vinces1979/node-def/blob/master/README.md
NB. My answer of 2016 is not correct and misleading as mentioned in comments.
Trying Node-6.4.0 ( process.versions.v8 = '5.0.71.60') and Node Chakracore-v7.0.0-pre8 and then Chrome-52 (V8=5.2.361.49), I've noticed that named parameters are almost implemented, but that order has still precedence. I can't find what the ECMA standard says.
>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }
> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17
But order is required!! Is it the standard behaviour?
> f(b=10)
a=10 + b=2 = 12
This is admittedly pseudocode, but I believe it'll work (I know it works in TypeScript; I'm adopting it for JavaScript).
// Target Function
const myFunc = (a=1,b=2,c=3) => {a+b+c}
// Goal usage:
myFunc(a=5, b=6) // 14
myFunc(c=0) // 3
// Set your defaults
const myFuncDefaults = {a:1, b:2, c:3};
// Override them with passed parameters
const myFuncParams = (params) => { return Object.assign(myFuncDefaults, params)}
// Use the overloaded dict as the input
const myFunc2 = (params) => {
let {a, b, c} = myFuncParams(params);
return myFunc(a, b, c)
}
// Usage:
myFunc({a:5, b:6}) // 14
myFunc({c:0}) // 3
// Written more succinctly:
const myFunc = (params) => {
let {a,b,c} = Object.assign({a:1, b:2, c:3}, params)
return a + b + c
}
For what it's worth, TypeScript makes this kind of nice with hinting:
interface IParams {
a: number;
b: number;
c: number;
}
const myFunc = (params: Partial<IParams>): number => {
const default: IParams = {a:1, b:2, c:3};
let {a, b, c} = Object.assign(default, params)
return a + b + c
}
Yes, well, kind of. I've found two solutions. I'll explain just one.
In this solution, we give up positional arguments, though.
We can use an object (almost identical to a dict in Python) to pass the arguments.
In this example, I'm using the function to generate the name of a image file:
// First we define our function with just ONE argument
function name_of_img(img_desc){
// With this step, any undefined value will be assigned a value
if(img_desc.size == undefined) {img_desc.size = "400x500"}
if(img_desc.format == undefined) {img_desc.format = ".png"}
console.log(img_desc.size + img_desc.format)
}
// Notice inside our function we're passing a dict/object
name_of_img({size: "200x250", format : ".jpg"})
// In Python name_of_img(size="200x250" , format="jpg")
// returns "200x250.jpg"
name_of_img({size: "1200x950"})
// In Python name_of_img(size="1200x950")
// returns "1200x950.png"
We can modify this example, so we can use positional arguments too, we can also modify it so non valid arguments can be passed, I think I will make a GitHub repository about this.
Contrary to what is commonly believed, named parameters can be implemented in standard, old-school JavaScript (for boolean parameters only) by means of a simple, neat coding convention, as shown below.
function f(p1=true, p2=false) {
...
}
f(!!"p1"==false, !!"p2"==true); // call f(p1=false, p2=true)
Caveats:
Ordering of arguments must be preserved - but the pattern is still useful, since it makes it obvious which actual argument is meant for which formal parameter without having to grep for the function signature or use an IDE.
This only works for booleans. However, I'm sure a similar pattern could be developed for other types using JavaScript's unique type coercion semantics.
Code A, this is OK and logs [ 1, 2, 3 ]
function fn() {
console.log(...arguments);
}
fn([1, 2, 3]);
Code B, this fails with SyntaxError: Unexpected token ...
Also, wrapping ...arguments in () won't help either.
function fn() {
var a = ...arguments;
}
fn([1, 2, 3]);
In both cases, I assume, we have a RHS lookup. Why is it OK to pass on ...arguments to console.log (or other function), but not to assign it to a variable?
PS. I know that this would never stand in real life code or there are other, better solutions to this. My question is purely theoretical/conceptual and limited to understanding why the different behavior occurs.
The two applications of the spread syntax are:
turn items of an iterable value into arguments of a function call
turn items of an iterable into elements of an Array
So this works:
function fn() {
var a = [...arguments];
}
It doesn't work as in CODE B... Invalid syntax
You can spread in fn params like
function fn(...params)
{
...
}
or Array and Object
var a = [1,2,3,4,5],
b = [6,...a];
var x = {a:1,b:1},
y = {c:1,...x}
I'm working on an open source project and stumbled over bitwise operators. I do understand the principles and also that javascript evaluates non-zero integer values to true (correct me here if I'm wrong; found this statement in an accepted answer in another post).
The code in question is as follows:
function example(){
var args = arguments;
var j = 1 & args[0];
.
.
.
}
var test = {keyA: 1, keyB: 2};
example(test);
My Question is: What's the value of j?
What is the binary equivalent of an object?
As far as i understand it, j = 0 if the last bit in test is 0 and j = 1if the last bit in testis 1.
Please help me out here guys. I spend the last hour searching any nearly related post here and most topics are about numbers, one or two were about booleans and that's that.
Edit:
As the code example given above doesn't seem to be as clear as i thought, here the full function as i found it (and working):
function Extend() {
var args = arguments;
var target;
var options;
var propName;
var propValue;
var deep = 1 & args[0];
var i = 1 + deep;
target = args[i - 1] || {};
for (; i < args.length; i++) {
// Only deal with non-null/undefined values
if (options = args[i]) {
// Extend the base object
for (propName in options) {
propValue = options[propName];
if (propValue !== undefined) {
propValue = options[propName];
target[propName] = (deep && IsPlainObject(target[propName])) ? Extend(deep, {}, propValue) : propValue;
}
}
}
}
// Return the modified object
return target;
}
var _someVariable = Extend({keyA: 1, keyB: 2, keyC: 10}, _someOtherVariable);
deephas to have some meaning as it determines whether to enter the FOR-loop ... or not.
The intent of the deep variable is to detect the difference between these two calls:
Extend({keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
and
Extend(true, {keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
The first variant will return this:
{keyA: {b: 2}, keyB: 2, keyC: 3}
The second is intended to return this:
{keyA: {a: 1, b: 2}, keyB: 2, keyC: 3}
So the function in fact allows for a first, optional argument, that will make the function apply the extension recursively so you get a deep instead of a shallow extended object.
You can also see this intent by analysing the recursive call, where the first argument is deep, the second is the object to extend, and the third the object to extend with.
The following line also shows this:
var i = 1 + deep;
As i is point where the loop will start from, you can see that if deep is set to 1 instead of 0, the loop will start processing from argument #2 onwards, which makes sense, as argument #0 was recognised as being the optional argument, and the next one is the target object.
Note that the function accepts a variable number of additional arguments which it will use to extend the target object with. It is over these arguments that the i variable loops.
As a side note: because of a bug, the second version returns the same as the first. To fix the bug, replace
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, {}, propValue) : propValue;
with:
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, target[propName], propValue) : propValue;
Now, coming to the essence:
var deep = 1 & args[0];
The use of the bitwise operator must have been an idea to have efficiency rule over clarity. The intent was to set deep to 1 if the first argument represented the optional argument, which should be a boolean indicating whether the extending should happen shallow or deep. As objects will make this expression evaluate to 0, it seemed like a nice trick.
But there is an issue with this. If one would like to do this:
Extend(["3"], {myattr: 2});
One would expect to get back an array-like object with an additional custom property myattr:
{0: "3", length: 1, myattr: 2}
However, the current Extend function will misinterpret the first argument as an instruction to perform a deep extension. This is because
1 & ["3"] will evaluate to 1 & 3, which evaluates to 1. And so the result will be the second argument without any extension happening:
{myattr: 2}
Conclusion: it is better to avoid such cryptic use of bitwise operators, and do something like this:
var deep = args.length > 0 && typeof args[0] === 'boolean' && args[0];
In common language: let deep be true (1) when there is at least one argument and that argument is a boolean and its value is true. In all other cases let it be false (0).
Note that one cannot pass false as the first argument, thinking that it will make the function perform a shallow extension. In this case,
that argument will be taken as the object to extend, which will fail. So the optional first argument, if provided, must be a boolean with value true.
This is true both for the original Extend function and the corrected one.
Finally, it would be good to add comments to this function to clarify the use of the first optional argument.
Bitwise operators do work on 32bit (un)signed integers. If you pass in anything that is not a number, it is implicitly coerced to a number. This is done using the valueOf/toString methods of the object as usual, and for your object {keyA: 1, keyB:2} will yield NaN. Then, this number is casted to an (U)int32, which gives 0 for NaN.
Check the spec for toUint32, follow it to ToNumber and on from there.
I have built an example using a couple of js classes for declaring Flag Enum and Flag Selections.
The source code is here in my github repo.
Basically to answer the question, and as mentioned by #Bergi, your class should implement valueOf() to return the value of the 'selections'.
// Example:
_w.Feature = new FlagEnum("Feature", {
CUSTOMER : "customer info" // 2
, ORDER : "order details" // 4
, DELIVERY : "delivery details" // 8
, DELIVERY_LIST : "listing of all deliveries" // 16
, DRIVER : "driver details" // 32
})
let [CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER] = Feature.get_values()
features = new FlagSel(Feature, CUSTOMER | ORDER | DELIVERY)
// -or-
features = new FlagSel(Feature, [CUSTOMER, ORDER, DELIVERY])
// Using in code
// Check feature using bitwise mask:
if (features & ORDER){
pc("features includes ORDER")
}
// -or-
// Check feature using has method:
if (features.has(ORDER)){
pc("features includes ORDER")
}
// Managing values:
features.add(CUSTOMER)
features.rem(ORDER)
// Print available options
console.log(Feature)
// output: <FlagEnum - Feature> options: CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER
// Print selected options
console.log(features)
// output: <FlagSel - Feature> CUSTOMER, ORDER, DELIVERY
I am reading the book "JavaScript-The Good Parts", in chapter 4.14 Curry, the book gives the following example:
Function.method('curry', function(){
var slice = Array.prototype.slice,
args = slice.apply(arguments), //1st-arguments
that=this;
return function(){
return that.apply(null, args.concat(slice.apply(arguments))); //2nd-arguments
}
})
var add1=add.curry(1);
document.writeln(add1(6)); // 7
I have two questions on this code:
There are two places using 'arguments'. In the method invoking in the last two lines code, is it so that '1' goes to the 1st-arguments and '6' goes to the 2nd-arguments?
There is a line of code apply(null, args.concat(slice.apply(arguments))), why does it apply(null,...) here?, what is the sense to apply a argument to a null object?
There are two places using 'arguments'. In the method invoking in the last two lines code, is it so that '1' goes to the 1st-arguments and '6' goes to the 2nd-arguments?
Yes, 1 is part of arguments of the outer function, while 6 goes the arguments in the inner function. The inner function can capture all other variables in a closure except for arguments and this, which have a special meaning inside a function, hence are not part of that closure. So that, and args are captured, but not arguments.
There is a line of code apply(null, args.concat(slice.apply(arguments))), why does it apply(null,...) here?, what is the sense to apply a argument to a null object?
Invoking a method with a null context will simply set the this value to the global object. In the case it seems the author does not care what that context is.
That example was kind of tricky for me too, because I'm not experienced in JavaScript, so I will try to explain it as I would have wished to be explained to me. Due to that reason it might be too explicit!
Also, before you start, I would recommend you to review the 'closure' part (for me to understand closure, was very helpful this quote):
"A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created." (from Mozilla developer network) - Closures: Line by Line explanation of "Javascript: Good Parts" example?
And now about the curry example:
apply(this, arguments) - this method can be applied to a function to call it and sends the 'this' variable and the parameters variables as an array (arguments).
For example:
// JSON objects
var ob1 = { // first object
a : 0,
b : 0
};
var ob2 = { // the second one
a : 0,
b : 0
};
// a function that updates 'a' and 'b'
function update(newA, newB) {
this.a = newA;
this.b = newB;
}
// 'this' is equal with ob1 and arguments array is [10, 20]
update.apply(ob1, [10, 20]);
// the same as above, but 'this' is here ob2
update.apply(ob2, [30, 40]);
/* after update:
ob1 {
a: 10,
b: 20
}
ob2 {
a: 30,
b: 40
}
*/
Now, that you have understood apply, you might ask why is in this example is called only with a single parameter.
args = slice.apply(arguments);
The function 'slice' takes an array and some parameters that represent indexes and forms a new array only with those.For example:
var anArray = ['red', 'green', 'black'];
var otherArray = anArray.slice(0); // after this line 'otherArray' will be ['red']
otherArray = anArray.slice(1,2); // 'otherArray' will be ['green','black']
// but what happens id you don't specify any indexes?
otherArray = anArray.slice();
// otherArray will be equal with ['red', 'green', 'black'], the same as 'anArray'
// it just makes a copy of it
So, when it does:
args = slice.apply(arguments)
is the same as:
args = slice.apply(/*this*/ arguments, /*arguments*/ undefined);
which is it 'almost' like saying:
args = arguments.slice(); // args will have all the elements the same as arguments
The reason why it does that is because args will be an array with all the methods of an array, but 'arguments' doesn't have any methods.
"Because of a design error, arguments is not really an array. It is an array-like object. Arguments has a length property, but it lacks all of the array methods." (from the book)
Let's recap, we need it these two lines:
var slice = Array.prototype.slice;
args = slice.apply(arguments);
just to make 'arguments' to have all the methods that are specific to the an array.
In our case we will need the 'concat' method that takes two array and joins them.
Function.method('curry', function(){
var slice = Array.prototype.slice;
args = slice.apply(arguments);
that=this; // saves this (which will be a function)
return function(){
// 'that' will be the same as this from above
// and is a function that we call it with the apply
return that.apply(/*this*/null, /*arguments*/ args.concat(slice.apply(arguments)));
// 'this' was null, an arguments was a join between 'args' and 'arguments'
}
});
Finally, you just have to understand how will be used:
function add(a, b) {
return a + b;
}
var add1 = add.curry(1); // add is function, and 'add.curry(1)' returns a function
// that will have 'a' set as 1(one) and 'b' as undefined(not being set)
var sum = add1(6); // 7
// when you call add1(6), you actually call that function that was returned by
// the line add.curry(1), with 'b' equal with 6