I am calling a function at several places within my app. This function takes several parameters whose values might change. To avoid re-typing, I want to save a reference to this function so that I can simply call this referred function everywhere. Here is the simplified code:
const func1 = (a,b,c) => a + b + c;
let a = 1, b = 2, c = 3;
const func2 = func1.bind(this, a, b, c);
func2();
//prints 6
c = 6;
func2();
//still prints 6!
How can I ge func1 to be executed with updated values of a, b and c by calling func2?
Use arrow function:
const func1 = (a,b,c) => a + b + c;
let a = 1, b = 2, c = 3;
const func2 = () => func1(a, b, c);
console.log(func2());
c = 6;
console.log(func2());
You can bind the function to an array of [a, b, c] instead, and then change the property at index 2:
const func1 = (a,b,c) => a + b + c;
const params = [1, 2, 3];
const func2 = () => func1(...params);
func2();
params[2] = 6;
func2();
If you only change c, you could consider binding the function to a and b, and then passing the changing c:
const func1 = (a,b,c) => a + b + c;
const params = [1, 2];
const func2 = (c) => func1(...params, c);
func2(3);
func2(6);
If you want to use params from scope where you declare your function, just skip those params in function signature
const f = () => a + b + c;
let a = 1, b = 2, c = 3;
console.log(f());
c = 6;
console.log(f());
Instead of this const func2 = func1.bind(this, a, b, c);
You can use this function(arrow): const func2 = () => func1(a, b, c);
Related
I want to write unit test case for fn1() following code:
function add(a, b){
const q = 5
console.log(a)
console.log(b)
const c = a + b
console.log(c)
console.log('1')
return c
}
function fn1(){
let a = 5;
let b = 6;
let c = obj.add(a, b);
console.log(a)
console.log(b)
console.log(c)
console.log('1')
return c;
}
And I want to pass different arguments to add(a, b) in fn1(). How can I do that using mocha, sinon, chai?
You can use sinon stub, stub the add method and call wrappedMethod, which is a reference to original method; in order to force pass different arguments to add method.
But you need to structurize your code a little bit.
Here is the simple example to show you how to do it.
I create method add and method fn1 inside check object on file check.js
// File: check.js
const check = {
add: (a, b) => {
const q = 5
console.log('add a:', a)
console.log('add b:', b)
const c = a + b
console.log('add c:', c)
console.log('add called');
return c
},
fn1: () => {
let a = 5;
let b = 6;
let c = check.add(a, b);
console.log('fn1 a:', a);
console.log('fn1 b:', b);
console.log('fn1 c:', c);
console.log('fn1 called');
return c;
},
};
module.exports = check;
And I create simple test file: check.spec.js
// File: check.spec.js
const sinon = require('sinon');
const check = require('./check');
describe('check', () => {
it('pass different argument to add()', () => {
sinon.stub(check, 'add').callsFake(
function () {
console.log('stub add:', arguments);
// Change the arguments here:
arguments['0'] = 7;
// Call write method with modified arguments.
return check.add.wrappedMethod.apply(this, arguments);
}
);
check.fn1();
});
});
I change the first argument a to 7. Here is the result when I run it at terminal:
$ npx mocha check.spec.js
check
stub add: [Arguments] { '0': 5, '1': 6 }
add a: 7
add b: 6
add c: 13
add called
fn1 a: 5
fn1 b: 6
fn1 c: 13
fn1 called
✓ pass different argument to add()
1 passing (4ms)
While going through features of JavaScript, I used default arguments and spread syntax in same function.
let whatIsThis = (a, b = 2, ...c) => {
console.log("a = " + a, "b = " + b,"c = " + c)
}
whatIsThis(a = 1, c = [2,3,4,5,6,7,8])
After running it, I expected output to be like this:
"a = 1"
"b = 2"
"c = 2,3,4,5,6,7,8"
But instead I got this:
"a = 1"
"b = 2,3,4,5,6,7,8"
"c = "
Why didn't this worked?
It's because you can't pass named arguments to a function in JavaScript. When you do whatIsThis(a = 1, c = [2,3,4,5,6,7,8]) what it really means is whatIsThis(1, [2,3,4,5,6,7,8]) (because a = 1 statement returns 1).
What you can do is move default argument to the end (which is generally a good practice) or wrap your arguments in objects. For example
let whatIsThis = ({a, b = 2, c}) => {
console.log("a = " + a, "b = " + b,"c = " + c)
}
whatIsThis({a: 1, c: [2,3,4,5,6,7,8]})
You could use undefined for the second parameter and use spread syntax ... for all other parameters of the function who are collected with rest parameters ....
JavaScript does not have named parameters.
You need to hand over the parameters in the same order as the function signature.
let whatIsThis = (a, b = 2, ...c) => {
console.log("a = " + a, "b = " + b, "c = " + c)
}
whatIsThis(1, undefined, ...[2, 3, 4, 5, 6, 7, 8])
// ^^^^^^^^^ takes default value
// ^^^^^^^^^^^^^^^^^^^^^^^^ spreads values for rest parameters
You need to call as whatIsThis(a = 1, undefined , c = [2,3,4,5,6,7,8]) because you are using a default parameter in the middle of the function parameter so that should be called as undefined to use the default value.
let whatIsThis = (a, b = 2, ...c) => {
console.log("a = " + a, "b = " + b,"c = " + c)
}
whatIsThis(a = 1, undefined , c = [2,3,4,5,6,7,8])
Javascript does not have named arguments. Arguments are assigned to parameters based only by position. You cannot assign arguments by name and you cannot simply skip the b argument. This:
whatIsThis(a = 1, c = [2,3,4,5,6,7,8])
Is equivalent to:
a = 1;
c = [2,3,4,5,6,7,8];
whatIsThis(a, c);
a = 1 here is an assignment operation creating a new global variable; it has nothing to do with the parameter a of the function.
The order of the function parameter matters. In this case the the function order is (a, b = 2, ...c) but the function is called with only two parameters whatIsThis(a = 1, c = [2,3,4,5,6,7,8]).
So basically the argument c is undefined when the function is called and the parameter b refers to the array [2,3,4,5,6,7,8].
Also note calling a function like this whatIsThis(a = 1, c = [2,3,4,5,6,7,8]) will led some linting tools and IDE to throw error.
let a = 'alpha', b = 'beta';
[a,b] = [b,a];
This swaps the values of a and b as intended;
but when placed inside a function it doesn't work
let c = 'charlie', d = 'delta';
swapVar = (x,y) => [x,y] = [y,x]
swapVar(c,d);
What am I missing here?
When you do
let a = 'alpha', b = 'beta';
[a,b] = [b,a];
You're swapping the values of a and b.
When you do
let c = 'charlie', d = 'delta';
swapVar = (x,y) => {
// x and y are separate variables scoped within this block
[x,y] = [y,x]
console.log(x,y); // it is swapped alright but isn't reflected on c and d
c = x;
d = y;
// Now the value will have been reflected.
}
swapVar(c,d);
So, within the function the values are swapped but aren't reflected outside. You could modify the program like this:
swapVar = (x,y) => [y,x]
[c, d] = swapVar(c, d); // now you're reflecting the swapped values on the outside
To have the intended effect.
You are doing the swap in a scope where the variables aren't being "exported".
In the first example, you act on the actual variables a and b in the scope they are defined in.
However, in the second example, you are acting on the variables x and y which are the same value as c and d but aren't the actual c and d since they are primitives so the c and d outside the scope of the arrow function is not affected.
{
let a = 'alpha',
b = 'beta';
console.log("Test 1");
console.log(`before a: ${a} b: ${b}`);
[a, b] = [b, a];
console.log(`after a: ${a} b: ${b}`);
}
{
let c = 'charlie',
d = 'delta';
console.log("Test 2");
console.log(`before c: ${c} d: ${d}`);
swapVar = (x, y) => [x, y] = [y, x]
/*
function swapVarExpanded(x, y) {
const tmp = [y, x];
x = tmp[0];
y = tmp[1];
// Doesn't actually matter
// because x and y die at the next closing curly brace due to scope
}
*/
swapVar(c, d);
console.log(`after c: ${c} d: ${d}`);
}
function partialize(){
}
function calculation(a,b,c){
console.log(a*b/c);
return a*b/c;
}
var a = 10, b= 20, c= 5;
var partialize1 = partialize(calculation, a);
partialize1(b,c)
var partialize2 = partialize(calculation, a, b);
partialize2(c)
var partialize3 = partialize(calculation, a, b, c);
partialize3()
I need to write partialize function which give same output in all three condition.
I tried like that it work .but i used spread operator .can we do this without spread operator ?
function partialize(fn,...a) {
console.log(...a);
return function (...b) {
console.log(...b);
fn(...a,...b);
}
}
function calculation(a, b, c) {
console.log(a * b / c);
return a * b / c;
}
var a = 10, b = 20, c = 5;
var partialize1 = partialize(calculation, a);
partialize1(b, c)
var partialize2 = partialize(calculation, a, b);
partialize2(c)
var partialize3 = partialize(calculation, a, b, c);
partialize3()
can we do the same thing without spread operator ?
You can save the initial arguments that were passed and return a function that can be called with the rest of the arguments, then calling the original function with apply:
function partialize(fn) {
const initialArguments = Array.from(arguments).slice(1);
return function() {
const finalArguments = Array.from(arguments);
fn.apply(null, initialArguments.concat(finalArguments));
}
}
function calculation(a, b, c) {
console.log(a * b / c);
return a * b / c;
}
var a = 10,
b = 20,
c = 5;
var partialize1 = partialize(calculation, a);
partialize1(b, c)
var partialize2 = partialize(calculation, a, b);
partialize2(c)
var partialize3 = partialize(calculation, a, b, c);
partialize3()
If your code is currently working as is but you'd like to change it to not use the spread operator, you can use the arguments object instead.
arguments object:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Also check out this stackoverflow question for some example code working with the arguments object if helpful. How can I convert the "arguments" object to an array in JavaScript?
user944513, to simulate an overload of methods in javascript, yo can use the arguments object, which comes by default in the functions. To explain you better, i've written a block of code. Hope this can help you:
function suma(a = 0){
let resultado = 0;
console.log(arguments.length);
for(let i = 0; i < arguments.length; i++)
{
if(typeof(arguments[i] == "number")){
resultado += arguments[i];
}
}
}
suma(1,2,3,4); // 10
suma(1,2) // 3
var add = function(a, b) {
return a + b;
}
var addOne =add.bind(null,1);
var result = addOne(4);
console.log(result);
Here the binded value of a is 1 and b is 4.
How to assign the binding value i.e)1 to the second argument of the function without using spread operator(...)
You could take a swap function with binding the final function.
var add = function (a, b) { console.log(a, b); return a + b; },
swap = function (a, b) { return this(b, a); },
addOne = swap.bind(add, 1),
result = addOne(4);
console.log(result);
With decorator, as georg suggested.
var add = function (a, b) { console.log(a, b); return a + b; },
swap = function (f) { return function (b, a) { return f.call(this, a, b) }; },
addOne = swap(add).bind(null, 1),
result = addOne(4);
console.log(result);
You could use the arguments object for reordering the parameters.
var add = function (a, b, c, d, e) {
console.log(a, b, c, d, e);
return a + b + c + d + e;
},
swap = function (f) {
return function () {
var arg = Array.apply(null, arguments);
return f.apply(this, [arg.pop()].concat(arg));
};
},
four = swap(add).bind(null, 2, 3, 4, 5),
result = four(1);
console.log(result);
You can use the following way
var add = function(x){
return function(y){
return x+y;
}
}
add(2)(3); // gives 5
var add5 = add(5);
add5(10); // gives 15
here add5() would set x = 5 for the function
This will help you what you need
var add = function(a) {
return function(b) {
return a + b;
};
}
var addOne = add(1);
var result = addOne(4);
console.log(result);
You can try this
function add (n) {
var func = function (x) {
if(typeof x==="undefined"){
x=0;
}
return add (n + x);
};
func.valueOf = func.toString = function () {
return n;
};
return func;
}
console.log(+add(1)(2));
console.log(+add(1)(2)(3));
console.log(+add(1)(2)(5)(8));