Weird behaviour of map and max in lodash - javascript

var a = [ [1,2,3], [4,5,6], [7,8,9] ];
_.map( a, _.max );
// gives [3, -Infinity, -Infinity]
I have tested it on my Chrome browser, on the lodash site.
Shouldn't the code above return [3, 6, 9]?
I can get the correct result with forEach:
var a = [ [1,2,3], [4,5,6], [7,8,9] ];
var result = [];
_.forEach( a, function(arr) { result.push(_.max(arr)); } );

Overall conclusion
I've opened an issue on GitHub: https://github.com/lodash/lodash/issues/379
Thanks to jdalton, the issue is now fixed. Sample: → jsFiddle
Details (why is the result 'weird'?)
I have never worked with Lodash in detail, but here are my researches:
Retrieves the maximum value of a collection. If the collection is empty or falsey -Infinity is returned.
— Lodash Documentation: _.max()
Testing _.max() with each group invidually worked perfectly:
_.max([1,2,3]); // 3
_.max([4,5,6]); // 6
_.max([7,8,9]); // 9
Now, I tried calling _.max() manually in the callback function of _.map():
var a = [ [1,2,3], [4,5,6], [7,8,9] ];
alert(_.map( a, function(val) {
return _.max(val);
}));
Works fine! So where is the difference between that and supplying _.max() as the second parameter?
_.map() actually sends 3 parameters to the callback function:
(value, index|key, collection).
— Lodash Documentation: _.map()
Consider the second parameter of _.max() now:
2.[callback=identity] (Function|Object|string): The function called per iteration. If a property name or object is provided it will be
used to create a ".pluck" or ".where" style callback, respectively.
— Lodash Documentation: _.max()
Conclusion: _.max() gets also passed the second and third parameter supplied by _.map(). The second parameter is important here! Passing truthy values (e.g. integers != 0) for it lets the function return -Infinity.
Test cases (→ jsFiddle):
alert(_.max([1,2,3], 0)); // 3
alert(_.max([1,2,3], 1)); // -Infinity
alert(_.max([1,2,3], 2)); // -Infinity
That is coming from the boolean checks performed in the source code:
https://github.com/lodash/lodash/blob/f0f7eee963966516490eb11232c9e9b4c6d0cc6c/dist/lodash.js#L3431
Because callback (the second parameter) is a truthy value, we will directly jump into the else branch. There, callback is reassigned as the following (the ternary operation will also take the else branch):
lodash.createCallback(callback, thisArg, 3);
createCallback() is defined here.
It returns the following function for our specific input parameters (these are 1, null, 3, see _.max() for details):
return function(object) {
return object[func];
};
Let's say, we save that in a variable called callback (→ jsFiddle):
var callback = _.createCallback(1, null, 3);
Calling that function with object = 1 (or 2, 3 or 6, etc.) results in undefined (that's pretty obvious).
Going back to _.max(), we see that there is a loop which compares the current value (from the callback function) to the initial/last value, and that is -Infinity as set at the beginning of the function.
undefined > -Infinity never results in true, so -Infinity will stay the 'maximum' value.

Related

for ... in - Is the object being iterated evaluated just once before entering the loop?

When I use a for ... in loop like:
for(var i in object) {}
I want to know if the object in question is evaluated just once or each time the loop, well, loops.
I made a quick test in my browser (also in node) like:
for(var i in (console.log('INIT'), [1, 2, 3, 4])) { console.log('KEY', i); }
and I get:
INIT
KEY 0
KEY 1
KEY 2
KEY 3
So from this empirical evidence, I could assume that is indeed only evaluated once.
But, is this behavior standard?
From the Mozilla documentation, a for...in loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype. An (enumerable) property that is deleted before it has been visited will not be visited later. Properties added to the object over which iteration is occurring may either be visited or omitted from iteration.
In short, the outcome of the example posted by #Amit is not guaranteed, although Chrome and IE may use a different specification for the for ..in loop. However, at least deleting an element seems to prevent it from being visited in Chrome:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
delete obj['c'];
}
Bear in mind that (console.log('INIT'), [1, 2, 3, 4]) is an expression that evaluates to [1, 2, 3, 4] so it's not a valid evidence of the issue. A better empirical evidence can be obtained with:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
obj.d = 4;
}
And we don't see "d"...
The ECMAScript® Language Specification, section 12.6.4 does not say much about this, except that the expression on the right side is evaluated once and cast to an object:
Let exprRef be the result of evaluating the Expression.
Let experValue be GetValue(exprRef).
If experValue is null or undefined, return (normal, empty, empty).
Let obj be ToObject(experValue).
This says nothing about evaluating any of the keys or values of that object at that time.
In fact, the part that follows the quoted paragraph suggests the keys could be retrieved during the iterations:
Repeat
Let P be the name of the next property of obj whose [[Enumerable]] attribute is true. If there is no such property, return (normal, V, empty).
But there is no requirement in either direction. So, ... this could be implementation (browser) dependent.
When you say that the object is evaluated just once, that can be have different meanings:
The object reference is evaluated just once. This is important when that object is the outcome of an expression, such as a function call. But this is surely taken for granted and not what you mean;
The object's keys (properties) are enumerated once, but the values are retrieved on demand;
The object's keys and values are retrieved once. This could be done at 1 level or nested levels at a potential high memory cost.
This test case shows in my browser (FireFox) the second happens, not the third:
var obj = {a: 1, b: 2, c: 3};
for (key in obj) {
document.write('obj[' + key + '] = ' + obj[key] + '<br>');
if (key=='a') {
// modify a value that is still to be visited
obj["c"] = 4;
// add a key/value pair
obj["d"] = 9;
}
}
Output is (as you can probably also see in your browser):
obj[a] = 1
obj[b] = 2
obj[c] = 4
So the keys were only retrieved once, the values on demand (i.e. not at the start of the loop).

How does bitwise-and operator work on objects in javascript?

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

Why does this curried method need to be wrapped by a function?

In the example below, I would expect that one could pass the curried function as a predicate to the any function. However, it only produces the correct result when the curried function is wrapped. Why does this behaviour occur?
var isGreaterThanOneCurried = _.curryRight(_.gt, 2)(1);
var isGreaterThanOneNoCurry = function(value) { return value > 1; };
var listOfOnes = [1, 1];
// CORRECT! returns false
_.any(listOfOnes, function(value) { return isGreaterThanOneCurried(value); });
// INCORRECT! returns true
_.any(listOfOnes, isGreaterThanOneCurried);
// CORRECT! returns false
_.any(listOfOnes, isGreaterThanOneNoCurry);
As described in the documentation for _.some (_.any is an alias for _.some):
The predicate is bound to thisArg and invoked with three arguments:
(value, index|key, collection).
Though you have curried from the right, the function still accepts multiple arguments (even though curried functions, by definition, are not supposed to accept multiple arguments, lodash contradicts that definition here). Those multiple arguments are supplied from left-to-right, so what you end up with is an arguments list that looks like this:
[1, 0, [1, 1], 1]
The first three are supplied by _.any, and the final one is one you supplied after right-currying.
You can verify this pretty easily:
var _ = require('lodash')
var listOfOnes = [1, 1]
function logArgsify(fn) {
return function() {
console.log(JSON.stringify(Array.from(arguments)))
return fn.apply(null, arguments)
}
}
var gt = logArgsify(_.gt)
var isGreaterThanOneCurried = _.curryRight(gt, 2)(1)
_.any(listOfOnes, isGreaterThanOneCurried)
// Output: [1,0,[1,1],1]
first argument is 1 (value)
second argument is 0 (index)
third argument is [1, 1] (collection)
fourth argument: 1, supplied earlier
_.gt only considers two arguments
1 > 0 is true

Functional programming in javascript - add(a)(b)(c)

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)

What is a difference between Array.prototype.forEach.call vs Array.prototype.forEach

According to documentation at MDN you can provide this argument to forEach function if invoked like this, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach, But it doesn't work. It works if i use call with it.
As i understand call and apply are used to supply this and arguments to function. However, there should be no need. So what am i missing?
It definitely does work, the second parameter to forEach supplies context to the callback
var numbers = [1,2,3,4];
var sum = {value: 0};
numbers.forEach(function(num){
this.value += num;
}, sum);
console.log(sum); // Object {value: 10}
Explanation
It's already in the documentation (emphasis mine):
15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
callbackfn should be a function that accepts three arguments.
forEach calls callbackfn once for each element present in the
array, in ascending order. callbackfn is called only for elements of
the array which actually exist; it is not called for missing elements
of the array.
If a thisArg parameter is provided, it will be used as the this
value for each invocation of callbackfn. If it is not provided,
undefined is used instead.
thisArg is only used in the invocation of callbackfn. It's not, however, used to provide the this value for forEach, where this needs to be an array like structure (that means it has a length property). If you use Array.prototype.forEach(..., someObject), the this value in forEach's context will be undefined.
Simplified forEach version (which shows the problem immediately)
function forEach( callback , thisArg ){
// The algorithm parses the length as UInt32, see step 3.
// >>> not only acts as bit shift, but also forces the
// value into an unsigned number.
var len = this.length >>> 0, // using "this", not "thisArg"!
i;
for(i = 0; i < len; ++i){
callback.call(thisArg, this[i]);
// thisArg ^^^^^^^^^ is used here, not up at length
}
}
// example calls:
var logArguments = function(args){
console.log(args, this);
}
forEach(logArguments, [1,2,3]); // logs nothing
forEach.call([1,2,3], logArguments); // logs 1, 2, 3
forEach.call([1,2,3], logArguments, [2,3,4]); // logs "1 Array [2,3,4]"
// "2 Array [2,3,4]"
// "3 Array [2,3,4]"

Categories