Can someone explain why the function below is not working (giving me an alert) when I try to call first(), however it works fine when I assign it to a new const?
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first() // does not work
const newFunc = first();
newFunc(); // works
Is this something specific to ES6 or am I missing something?
Thank you everyone! I had a brain fart, I kept focusing on the new syntax thinking that I made a mistake or it works in a different way, but I was never calling the second function returned by the first one. I changed it to:
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first()
It works now!
first() works just fine and returns the second() function, but I don't think you expected this. And your try to copy it used () and thus called it, returning the second function. After that newFunc contains second and calling it gives you the intended result.
first() only returns a function object - therefor another set of () is needed to actually call that returned function.
It doesn't need assignment to const newFunc though - first()(); would get you your alert as well.
This technique of having a function return another function, or an object that exposes several functions that can then in turn be called, is know as Revealing Module Pattern.
You're returning "second" as a function, but you never execute, you have 2 options, return "second()" or execute after receive it.
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first()(); // does work
//Alternative
const secondTime = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second();
}
secondTime();
Hope this works.
Related
I have started learning promises in JS, and there are (resolve, reject) which are passed to promise. After some actions in the function you call resolve() if there is everything OK and reject() if not. So, that's why I am asking about this.
Can we actually call the parameters of a function inside of it? Actually, if I put () after the parameter inside a function in VS Code, it is highlighted as a function.
Sorry, if there is some issues with explaining. I am not a native speaker...
There is an example: (what is stack() actually?)
const iGotIt = true;
const f = (stack, overflow) => {
if (iGotIt) {
stack({
newKnowledge: 'Finally',
message: ':)'
})
}
}
It depends on the function parameter, since it may not be a function.
For example:
myFunction(data, callback){
const result = do_something_with_data();
callback(result);
}
myFunction(0, result => {
do_something_with_result();
}); //works
myFunction(1, console.log); //works
myFunction(2, 0); //doesn't work, 0 is not a function.
what is stack() actually?
It's the first parameter in the f function.
The f function expects the first parameter to itself also be a function, and one which accepts at least one parameter which is an object.
But what stack actually is depends on what gets passed to f.
For example, consider this usage in which a function is passed as the first parameter:
const iGotIt = true;
const f = (stack, overflow) => {
if (iGotIt) {
stack({
newKnowledge: 'Finally',
message: ':)'
})
}
}
f(x => console.log(x));
Then invoking stack() invokes the function that was provided. Alternatively, consider this example:
const iGotIt = true;
const f = (stack, overflow) => {
if (iGotIt) {
stack({
newKnowledge: 'Finally',
message: ':)'
})
}
}
f();
This fails because nothing was provided, so stack is undefined. Or this example:
const iGotIt = true;
const f = (stack, overflow) => {
if (iGotIt) {
stack({
newKnowledge: 'Finally',
message: ':)'
})
}
}
f('test');
This also fails, because a string is not a function and can't be invoked like one.
I have the following scenario:
file1.js:
async function fctionA(event) {
console.log('In fctionA()!');
let responseA = null;
const formattedEvent = formatEvent(event);
...
const b = await fctionB(formattedEvent);
responseA = someLogicUsing(b);
return responseA; // responseA will depend on 'b'
}
file2.js:
async function fctionB(formattedEvent) {
console.log('Now in fctionB()!');
let resB = null;
...
const c = await fctionC(formattedEvent);
...
resB = someLogicDependingOn(c); // resB will depend on 'c'
return resB;
}
async function fctionC(formattedEvent) {
console.log('AND now in fctionC()!');
let c = await someHttpRequest(formattedEvent);
...
return c;
}
Side notes:
Don't mind formatEvent(), someLogicUsing() orsomeLogicDependingOn() too much. Assume it's just sync logic using provided data)
formattedEvent would be anything depending on the original input event. Just to note functions will use it.
PROBLEM:
What i want to do is to unit test fctionA(), using Jasmine: I want to check the responseA after appying the logic on fctionB(), but mock the result of fctionC().
My (clearly) naive approach was:
file1.spec.js
import * as Handler from '../src/file1';
import * as utils from '..src//file2';
describe('fctionA', () => {
let response = null;
beforeAll(async () => {
const mockedEventA = { mockedInput: 'a' };
const mockedC = { mockedData: 1 };
const expectedResponse = { mockedResponse: 1234 };
spyOn(utils, 'fctionB').and.callThrough());
spyOn(utils, 'fctionC').and.returnValue(Promise.resolve(mockedC));
response = await Handler.fctionA(mockedEventA);
});
it('should return a proper response', () = {
expect(response).toEqual(expectedResponse);
});
});
But after checking logs, i can see that ´fctionC()´ does get executed (when as far as i understood, it shouldn't), therefore does not return the mocked result.
Then, after some try and error, i invoked fctionC() directly in fctionA() (instead of indirectly invoking it through´fctionB()´) just to see what happens, and I can spy it and return a mocked value. fctionC() does not execute (can't see log).
So, that makes me think that, at least the way I'm trying to spy on functions, only work for functions that are directly invoked by the function I'm calling, but not for nested ones-
I'm clearly not an expert in Jasmine, so I can't figure out another option. I looked a lot into docs and posts and blogs but nothing worked for me.
Is there a way to achieve what I try here? I guess I might be doing something really silly or not thinking it through.
Thanks!
onceCopy function (testFunc) {
const copyFunc = (a) => {
const copyFunc2 = (b) => {
return testFunc(a);
};
return copyFunc2;
};
return copyFunc;
};
So the function returns the inner function upon first invocation.
Then returns the inner function of the inner function of the second invocation.
Then the second inner function (third invocation) actually returns the passed argument in the parent function and only invokes it with the character we gave it on the second invocation.
Ideally I want to achieve what I'm achieving over many invocations after only the first one if that makes sense.
Edit: Yes sorry, _.once.
Edit: so first invocation onceCopy SHOULD hold a copy of the Func passed
Second invocation SHOULD trigger the copy and gives an ouput
Third invocation SHOULD give the result of the second invocation so should the fourth, fifth, sixth and so on...
My function does do this, but on the second invocation it stores a function (copyFunc2) again, but I just made that because I need somewhere to store "a".
so like we have
function multiplyBy3 (a) {return a*3}
and then once copy stores a copy of multiplyBy3
const actualFunction = onceCopy(multiplyBy3)
then upon second and third invocation what I want
actualFunction(1) = 3
actualFunction(66) = 3
so the passed function ONLY RUNS ONCE
Cant explain more than this, its in the lodash docs.
I'm not familiar with the function you're trying to reimplement, so feel free to correct me if I misunderstood. To wrap a function and ensure it's only called once you don't need multiple nested wrappings, only one with some state.
You need to keep track of whether you already have a result to return (hasResult) and if so, what that result is (result). Keeping these two variables separate allows you to cover the case when result is undefined while keeping the code easy to read and understand.
function once(wrappedFunction) {
let hasResult = false;
let result;
return (...args) => {
if (hasResult) {
return result;
}
result = wrappedFunction.apply(this, args);
hasResult = true;
return result;
}
}
// An example function to wrap
function multiply(a, b) {
return a * b;
}
const demoFunction = once(multiply)
console.log(demoFunction(1, 2)); // 2
console.log(demoFunction(3, 4)); // 2
console.log(demoFunction(5, 6)); // 2
Is this what you were looking for?
The initial function return is kept on subsequent calls. I used a second variable called in case the first call returns undefined, which should also be returned on subsequent calls.
const once = (onceFn) => {
let called;
let value;
return (...args) => {
if (called) return value;
called = true;
return (value = onceFn(...args));
};
};
function multiplyBy3(a) {
return a * 3;
}
const fn = once(multiplyBy3);
console.log(fn(3)); // 9
console.log(fn(66)); // 9
After calling the function for the 1st time, and getting the result, create a new function that returns the result, and use it whenever the wrapped function is called:
const once = fn => {
let func
return (...args) => {
if(func) return func()
const result = fn(...args)
func = () => result
return result
}
}
const multiply = (a, b) => a * b
const demoFunction = once(multiply)
console.log(demoFunction(1, 2)); // 2
console.log(demoFunction(3, 4)); // 2
console.log(demoFunction(5, 6)); // 2
Can I execute functions this way?
const test = testFunc() // returns "value" or undefined
test && anotherFunction()
Basically I want to execute anotherFunction() if test const is defined, otherwise just skip it.
I know that I can use something like this:
if (test) {
anotherFunction()
}
but I'm interested why the first method isn't working.
I will appreciate if someone explain me the difference between if () {} and &&.
// I'm confused because if I trying to use the first method I get:
Expected an assignment or function call and instead saw an expression
in my IDE.
The approach will work as expected you can see the below two cases as you mentioned.
First Case - testFunc returns some value
const testFunc = () => 1
const anotherFunction = () => 2
const test = testFunc()
test && anotherFunction()
Second Case - testFunc returns undefined
const testFunc = () => undefined
const anotherFunction = () => 2
const test = testFunc()
test && anotherFunction()
I hope this will help to understand it better.
Is there a way to do this in JS
function namedFunction(elements,args) {
const domElements = document.querySelector(elements);
const initialValue = 0;
let incrementBy = 5;
return function() {
// Do something to domElements based on initialValue and incrementBy
// function needs to run the first time namedFunction is called
// and this is the only function that needs to run on subsequent calls to namedFunction
}.call(null)
// the .call does not work as intended here, but this is basically what I want to do.
}
I think I can do namedFunction()() with the code above in order to invoke both, but I'm wondering if there is another way.
The longer version of the function would look like this:
function namedFunction(elements,args) {
const domElements = document.querySelector(elements);
const initialValue = 0;
let incrementBy = 5;
function namedFunctionEventHandler() {
// Do something to domElements based on initialValue and incrementBy
// function needs to run the first time namedFunction is called
// and this is the only function that needs to run on subsequent calls to namedFunction
}
namedFunctionEventHandler();
return namedFunctionEventHandler;
}
The goal would be to pass a single function as an event handler, that the first time it runs it does initial calculations, caches dom elements and the more heavier stuff, then executes the logic that is abstracted in the returned function and on subsequent calls it uses the data from the closure.
Edit: the namedFunction does not need to accept any arguments, its just for demonstration purposes.
document.addEventListener('scroll', namedFunction)
is what I want to be able to do.
#CertainPerformance - Sorry, I misread your answer.
If you take a look at the end result I would like to achieve, your proposition wont actually work as intended, as if I pass an invoked function as an event handler, its gonna run before an event has actually happened.
You can make namedFunction into an IIFE that saves a reference to a function (initially undefined). On call, if that variable is undefined, carry out the expensive calculations and then assign to the variable; if the variable is defined, then simply call it.
const handler = (() => {
let cheapFn;
return () => {
if (cheapFn) {
cheapFn();
return;
}
// expensive calculations here
const domElements = document.querySelector(elements);
...
cheapFn = () => {
// assign to cheapFn
};
cheapFn();
};
})();
Demo:
const handler = (() => {
let cheapFn;
return () => {
if (cheapFn) {
cheapFn();
return;
}
// expensive calculations here
console.log('expensive');
cheapFn = () => {
console.log('cheap');
};
cheapFn();
};
})();
document.addEventListener('scroll', handler);
body {
height: 400px;
}
body
You can take advantage of the fact that functions in JavaScript are first-class objects, and store the function state (initialized/uninitialized) in a property of the function.
The data computed during initialization can be stored in the function properties as well, please take a look at the demo:
const namedFunction = function(elements,args) {
if (!namedFunction.isInitialized) {
console.log('Initialization: Computing initial value...');
namedFunction.initialValue = 10 * 10;
console.log(`Initial value: ${namedFunction.initialValue}`);
namedFunction.isInitialized = true;
}
return function() {
console.log('Running regular operation:');
console.log(`Current value: ${--namedFunction.initialValue}`);
}.call(null)
}
document.getElementById('demo').addEventListener('click', namedFunction);
<button id="demo">Run</button>