Javascript: return multiple values from different functions - javascript

I am trying to return multiple values from different functions.
The starting point is a bidimensional array. An example of the code is:
var items = [[0,1],[1,2],[0,2]];
var a;
var b;
function first() {
a = items[Math.floor(Math.random() * items.length)];
return a;
}
function second() {
b = a[Math.floor(Math.random() * 2)];
return b;
}
function third (){
first();
second();
}
third();
If I write the code outside the functions, everything works fine. When I use functions and replace return with console.log, it works. If I use functions and return (as in the code reported above), it gives me undefined. I didn't find solutions. Why the code isn't working?
Thanks in advance

If you are declaring variable a and b outside function(like in your code) than there is no need to return the values. a and b will get defined.
But if you are not declaring it outside, then store the return values in array variable.
var items = [[0,1],[1,2],[0,2]];
function first() {
a = items[Math.floor(Math.random() * items.length)];
return a;
}
function second() {
b = a[Math.floor(Math.random() * 2)];
return b;
}
function third (){
var a = first();
var b = second();
var arr = [];
arr.push(a);
arr.push(b);
return arr
}
var t = third();
console.log(t[0], t[1]);

If you want third to return values, add a return in it.
function third (){
var a = [];
a.push(first())
a.push(second())
return a;
}

Maybe you want something like
function third (){
return {a: first(), b: second()};
}
then
var t = third()
console.log(t.a, t.b)
or if you're running on ES6
var {a,b} = third()
console.log(a, b)
see Destructuring assignment for further details

Related

Why does the default JS bind function works and why my polyfill for the bind returns undefined?

I am trying to write the polyfill for the js bind function over a multiply function. The js bind function is giving the correct answer 8 but my polyfill is giving undefined. The main multiply function is returning all the params correctly though.
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
obj.apply(args[0], [...params, ...param2]);
};
};
let mul = (a, b) => {
console.log(13, a, b, a * b);
return a * b;
};
let mulFour = mul.bind(this, 4);
let myMulFour = mul.myBind(this, 4);
console.log(mulFour(2));
console.log(myMulFour(2));
CertainPerformance was correct, needed to return the obj.apply(args[0], [...params, ...param2]); again.
The polyfill would go like this:
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
return obj.apply(args[0], [...params, ...param2]);
};
};

Javascript: How to store a declared function in a variable?

I'm learning Javascript and wondering if it's possible to store a declared function in a variable to be used later?
For context,
function add(a, b) {
return a + b;
}
var addTogether = _.partial(add, 1);
doSomething() // returns a promise that resolves to a 2
.then(addTogether); // expect to return 3
Is there a way to achieve this?
var Add = function (a, b)
{
return a + b;
}
var result = Add (2, 3);
Absolutely. Functions ARE data in JavaScript.
var foo = function(a, b) {
return a + b;
}
Is perfectly legitimate.
function add(a, b) {
return a + b;
}
var foo = add;
console.log(foo(5,10));
console.log(add(10, 20));
You can also use ES6 syntax to store anonymous functions in constants, like so:
const add = (a, b) => a + b;
const addOne = a => add(a, 1);
console.log(add(5, 10)); // 15
console.log(addOne(5)); // 6

Lodash partial with object path

Using lodash or arrow functions, what is the more elegant way to rewrite the func declaration in the following example ?
function multiply(a, b) {
return a * b;
}
let foo = {};
let func = function (v) { return multiply(v, _.get(foo, 'bar')) };
foo.bar = 4;
console.log(func(4)); //Result in 16
let foo2 = {};
let func2 = _.unary(_.partialRight(multiply, _.get(foo2, 'bar')));
foo2.bar = 4;
console.log(func2(4)); //Result in NaN
let foo3 = {};
let func3 = (v) => multiply(v, _.get(foo3, 'bar'));
foo3.bar = 4;
console.log(func3(4)); //Result in NaN
I tried with arrow function and partial but can't get it to work as you can see
Your third option is working.
The second option is not working, because _.get(foo2, 'bar') get's immediately evaluated and puts foo2.bar in partialRight as a parameter, which is undefined, because the 4 get's assigned later.
Therefore multiply calculates 4 * undefined which is NaN.
Improvements could be:
curry multiply
make func pure
For example:
const multiply = _.curryRight(function(a, b) {
return a * b;
})
let foo3 = {};
foo3.bar = 4;
let func3 = multiply(_.get(foo3, 'bar'));
console.log(func3(4));

Creation of array and append value inside closure in javascript

I am using this code -
var gArray = (function (value) {
var array = [];
return function () {
array.push(value);
return array;
}
}());
gArray(1);
gArray(2);
gArray(3);
I am expecting to this code snippet [1, 2, 3]
but i am getting [undefined, undefined, undefined]
The gArray function doesn't have an argument, the immediately invoked function does, but you pass nothing when you call it:
var gArray = (function (value) { //<- Argument of IIFE
var array = [];
return function () { //<- No arguments for gArray
array.push(value);
return array;
}
}()); //<- No arguments passed to IIFE
What you need is to define an argument for the returned function, which is gArray:
var gArray = (function () {
var array = [];
return function (value) {
array.push(value);
return array;
}
}());
Your outer function is a self-invoked function. That means that it will be executed as soon as () is reached. In this particular case, it's returning:
function () {
array.push(value);
return array;
}
which is taking value as undefined. To solve this issue, you can rewrite your code as follows:
var gArray = (function () {
var array = [];
return function (value) {
array.push(value);
return array;
}
}());
Change var array = []; to this.array = [];.
It needs to have the right scope.
var myArray = [];
function addToArray(value){
myArray.push(value);
console.log(value + " was added to " + myArray);
}
addToArray(1);
addToArray(2);
addToArray(3);
If you give back myArray console will say [1, 2, 3]
This is the best way to do it:
const array = [];
const pushArray = function(value, array) {
array.push(value);
return array;
};
pushArray(1, array);
pushArray(2, array);
pushArray(3, array);

new Function() with variable parameters

I need to create a function with variable number of parameters using new Function() constructor. Something like this:
args = ['a', 'b'];
body = 'return(a + b);';
myFunc = new Function(args, body);
Is it possible to do it without eval()?
Thank you very much, guys! Actually, a+b was not my primary concern. I'm working on a code which would process and expand templates and I needed to pass unknown (and variable) number of arguments into the function so that they would be introduced as local variables.
For example, if a template contains:
<span> =a </span>
I need to output the value of parameter a. That is, if user declared expanding function as
var expand = tplCompile('template', a, b, c)
and then calls
expand(4, 2, 1)
I need to substitute =a with 4. And yes, I'm well aware than Function is similar to eval() and runs very slow but I don't have any other choice.
You can do this using apply():
args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);
Without the new operator, Function gives exactly the same result. You can use array functions like push(), unshift() or splice() to modify the array before passing it to apply.
You can also just pass a comma-separated string of arguments to Function:
args = 'a, b';
body = 'return(a + b);';
myFunc = new Function(args, body);
On a side note, are you aware of the arguments object? It allows you to get all the arguments passed into a function using array-style bracket notation:
myFunc = function () {
var total = 0;
for (var i=0; i < arguments.length; i++)
total += arguments[i];
return total;
}
myFunc(a, b);
This would be more efficient than using the Function constructor, and is probably a much more appropriate method of achieving what you need.
#AndyE's answer is correct if the constructor doesn't care whether you use the new keyword or not. Some functions are not as forgiving.
If you find yourself in a scenario where you need to use the new keyword and you need to send a variable number of arguments to the function, you can use this
function Foo() {
this.numbers = [].slice.apply(arguments);
};
var args = [1,2,3,4,5]; // however many you want
var f = Object.create(Foo.prototype);
Foo.apply(f, args);
f.numbers; // [1,2,3,4,5]
f instanceof Foo; // true
f.constructor.name; // "Foo"
ES6 and beyond!
// yup, that easy
function Foo (...numbers) {
this.numbers = numbers
}
// use Reflect.construct to call Foo constructor
const f =
Reflect.construct (Foo, [1, 2, 3, 4, 5])
// everything else works
console.log (f.numbers) // [1,2,3,4,5]
console.log (f instanceof Foo) // true
console.log (f.constructor.name) // "Foo"
You can do this:
let args = '...args'
let body = 'let [a, b] = args;return a + b'
myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3
If you're just wanting a sum(...) function:
function sum(list) {
var total = 0, nums;
if (arguments.length === 1 && list instanceof Array) {
nums = list;
} else {
nums = arguments;
}
for (var i=0; i < nums.length; i++) {
total += nums[i];
}
return total;
}
Then,
sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;
If you want more, could you please provide more detail? It's rather difficult to say how you can do something if you don't know what you're trying to do.
A new feature introduced in ES5 is the reduce method of arrays. You can use it to sum numbers, and it is possible to use the feature in older browsers with some compatibility code.
There's a few different ways you could write that.
// assign normally
var ab = ['a','b'].join('');
alert(ab);
// assign with anonymous self-evaluating function
var cd = (function(c) {return c.join("");})(['c','d']);
alert(cd);
// assign with function declaration
function efFunc(c){return c.join("");}
var efArray = ['e','f'];
var ef = efFunc(efArray);
alert(ef);
// assign with function by name
var doFunc = function(a,b) {return window[b](a);}
var ghArray = ['g','h'];
var ghFunc = function(c){return c.join("");}
var gh = doFunc(ghArray,'ghFunc');
alert(gh);
// assign with Class and lookup table
var Function_ = function(a,b) {
this.val = '';
this.body = b.substr(0,b.indexOf('('));
this.args = b.substr(b.indexOf('(')+1,b.lastIndexOf(')')-b.indexOf('(')-1);
switch (this.body) {
case "return":
switch (this.args) {
case "a + b": this.val = a.join(''); break;
}
break;
}
}
var args = ['i', 'j'];
var body = 'return(a + b);';
var ij = new Function_(args, body);
alert(ij.val);
Maybe you want an annoymous function to call an arbitary function.
// user string function
var userFunction = 'function x(...args) { return args.length}';
Wrap it
var annoyFn = Function('return function x(...args) { return args.length}')()
// now call it
annoyFn(args)
new Function(...)
Declaring function in this way causes
the function not to be compiled, and
is potentially slower than the other
ways of declaring functions.
Let is examine it with JSLitmus and run a small test script:
<script src="JSLitmus.js"></script>
<script>
JSLitmus.test("new Function ... ", function() {
return new Function("for(var i=0; i<100; i++) {}");
});
JSLitmus.test("function() ...", function() {
return (function() { for(var i=0; i<100; i++) {} });
});
</script>
What I did above is create a function expression and function constructor performing same operation. The result is as follows:
FireFox Performance Result
IE Performance Result
Based on facts I recommend to use function expression instead of function constructor
var a = function() {
var result = 0;
for(var index=0; index < arguments.length; index++) {
result += arguments[index];
}
return result;
}
alert(a(1,3));
function construct(){
this.subFunction=function(a,b){
...
}
}
var globalVar=new construct();
vs.
var globalVar=new function (){
this.subFunction=function(a,b){
...
}
}
I prefer the second version if there are sub functions.
the b.apply(null, arguments) does not work properly when b inherits a prototype, because 'new' being omitted, the base constructor is not invoked.
In this sample i used lodash:
function _evalExp(exp, scope) {
const k = [null].concat(_.keys(scope));
k.push('return '+exp);
const args = _.map(_.keys(scope), function(a) {return scope[a];});
const func = new (Function.prototype.bind.apply(Function, k));
return func.apply(func, args);
}
_evalExp('a+b+c', {a:10, b:20, c:30});

Categories

Resources