Writing Javascript – Functions for newbie

Hello! This is a question that might be stupid, but trying to wrap my head around writing JS is taking it's toll. So look at this code block from codecademy JS intro course, using function as a parameter inside another function:
const higherOrderFunc = param => {
param();
return `I just invoked ${param.name} as a callback function!`
}

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}

higherOrderFunc(anotherFunc);
const higherOrderFunc = param => {
param();
return `I just invoked ${param.name} as a callback function!`
}

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}

higherOrderFunc(anotherFunc);
Is there a structural convention that the higher-order function is declared first? Logically in my head you would declare the anotherFunc first, then the higherOrderFunc, because that is using the other one. As a metaphor: Baking a cake you would get all specific ingredients ready first, then put it all together. This is just a question out of curiosity, and trying to understand the "unwritten rules", because I know they are as important as actual coding ...
28 Replies
Jochem
Jochem2y ago
have you tried running it and seeing what happens when you flip the declaration order?
Å Marlon G
Å Marlon G2y ago
The same result ... It prints: I just invoked anotherFunc as a callback function!
Zoë
Zoë2y ago
I would agree that anotherFunc should go above higherOrderFunc. It makes sense to have dependencies below and higherOrderFunc is relying on anotherFunc Programs where reading top to bottom never coming across something that hasn't been declared yet are really nice to work with and they organise themselves
Jochem
Jochem2y ago
there's no dependency though, the connection between higherOrderFunc and anotherFunc doesn't exist until the last line of the codeblock. They're both defined, and just sitting there in memory, and then anotherFunc is passed as an argument to higherOrderFunc there could be half a dozen other justAnotherFunc and yetMoreFunc, and they'd all be valid parameters for higherOrderFunc in practice, those probably won't even be declared in the same file
Zoë
Zoë2y ago
It's not a true dependency but it's still an unknown when you come across it reading top to bottom While if you have anotherFunc above you've at least seen it before the thing that uses it
Jochem
Jochem2y ago
but anotherFunc isn't mentioned in higherOrderFunc
const higherOrderFunc = param => {
param();
return `I just invoked ${param.name} as a callback function!`
}
const higherOrderFunc = param => {
param();
return `I just invoked ${param.name} as a callback function!`
}
Zoë
Zoë2y ago
No but it's still passed to it
Jochem
Jochem2y ago
yes, after you've read both function definitions
Zoë
Zoë2y ago
Also if this was written in Typescript you'd want to type param and you're going to end up with a type for a function that hasn't been seen yet
Jochem
Jochem2y ago
regardless, it's a bit of a moot point. It's very uncommon to write a callback and a function that takes that callback in the same file. A lot of the time, the callbacks will just be defined inline when you call the function
Å Marlon G
Å Marlon G2y ago
I guessed I would start an infinite loop when asking this question ... My basic question is really – and this is obviously theoretical, not practical: Would a boss go mental if I wrote it the other way around, because of an unwritten convention? And of course, this is from a beginners course ...
Zoë
Zoë2y ago
Use whichever order the style guide says, or if it's your project whatever order you prefer
Jochem
Jochem2y ago
it's a demonstration of a principle that you won't run into in production code in quite this way and even if a manager or senior takes issue, they'll just tell you and you can reverse them
Å Marlon G
Å Marlon G2y ago
Great! Thank you both! One has to take some kind of course for learning, and I know these issues of "understanding" will come up, but its just good to get it aired out for my own sake ...
WebMechanic
WebMechanic2y ago
@Å Marlon G the order would only become relevant had you used anotherFunc() literally inside higherOrderFunc. Since it's passed as a parameter it only needs to be available at runtime. As Jochem suggested, each could be in their own import module. They only need to be available (loaded) if the compiler hits the higherOrderFunc(anotherFunc); line. I disagree that callbacks are rarely in the same file as their caller or only appear as inline functions. It depends on the callback's job and scope. You could have a single DOM event handler or helper to serve multiple callees all in the same file. Enjoy writing Promises then 😋
Jochem
Jochem2y ago
still doesn't matter actually, unless you call higherOrderFunc before defining anotherFunc
const higherOrderFunc = () => {
console.log(anotherFunc());
return `I just invoked ${param.name} as a callback function!`
}

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}

console.log(higherOrderFunc());
const higherOrderFunc = () => {
console.log(anotherFunc());
return `I just invoked ${param.name} as a callback function!`
}

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}

console.log(higherOrderFunc());
works perfectly fine
const higherOrderFunc = () => {
console.log(anotherFunc());
return `I just invoked ${param.name} as a callback function!`
}

console.log(higherOrderFunc());

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}
const higherOrderFunc = () => {
console.log(anotherFunc());
return `I just invoked ${param.name} as a callback function!`
}

console.log(higherOrderFunc());

const anotherFunc = () => {
return 'I\'m being invoked by the higher-order function!';
}
This complains about accessing anotherFunc before initialization though
WebMechanic
WebMechanic2y ago
your second example is what I meant by "available at runtime". For the same reason it would bail on the next line containing ${param.name} however...
const higherOrderFunc = () => {
console.log(anotherFunc());
}
console.log(higherOrderFunc());
function anotherFunc() {
return 'I\'m being invoked by the higher-order function!';
}
const higherOrderFunc = () => {
console.log(anotherFunc());
}
console.log(higherOrderFunc());
function anotherFunc() {
return 'I\'m being invoked by the higher-order function!';
}
would work again 🙂
Jochem
Jochem2y ago
mostly because javascript's scoping is a mess 😄 (to explain, defining something with the function keyword hoists the declaration to the top of the file at runtime) ((Also when you use the var keyword, the variable initialization (though not assignment) is hoisted. But don't use var in 2023 ever, only villains do that))
WebMechanic
WebMechanic2y ago
debugging JS was so much more fun before there was let and const ... "Where's the var? Where is it? Come here..." Just remember: those who know the rules are also free to bend them at their will.
Å Marlon G
Å Marlon G2y ago
I think the main take away is indeed that scoping is quiet tricky to grasp ... This is the section of the course which addresses abstraction concepts, and it gives the example that by saying "I baked a cake" implies a lot of actions that we understand without it having to be explained directly (like mixing ingredients, pre-heating the oven, etc.). Therefore it is also the task of learnign to be specific and precise (and naming things ...), which gives me the most headache ... But interestingly, in my former life, I had to learn sign language for a dance piece, and sign language is in many ways a bit similar to coding. You can't really imply things in the same way as you can with spoken language, and therefore it is very precise and concise. As an example, signing "I rode the bike yesterday" you would first establish riding a bike, and then you could use that variable, so to speak, and say in what context you did it (yesterday). In practice, at least as much as I can remember, you would place the "the riding bike" variable visually over your right shoulder, for example, and then point to it for reference, and then sign the "yesterday". ... hmm ... so this means when writing:
function functionName()
function functionName()
moves that declaration before all other code which itself is not a function? And: is this true only when using the keyword, meaning that all functions written with => is not moved to the top, or are all functions regardless of how you write them moved to the top?
Jochem
Jochem2y ago
You don't use the equals sign with the function keyword, but other than that it's correct. Only ones declared with function are moved
Å Marlon G
Å Marlon G2y ago
Changed it to parenthesis, in case some other newbie was reading this. 💩 So, basically in a JS file, all the functions declared with function is run first, is that the practical meaning of this? And What about the => functions? Are they run in order, or are there more of these prioritizing effects? Finally – why is it done this way? What's the practical use of this?
Jochem
Jochem2y ago
they're not run, they're defined and it's likely a leftover from previous versions of javascript maintained for backwards compatibility you can technically use it, but I wouldn't recommend it. The way modern JS is used, most things are defined in imports so it's not something to worry too much about
Å Marlon G
Å Marlon G2y ago
Ah, ok ... so it's like the baking cake metaphor, they are just prepared to be run in order later.
Jochem
Jochem2y ago
prepared to be run when called, yes. In the baking metaphor, the JS engine reads the entire recipe and then sets aside certain ingredients (function and var) ahead of time so they're accessible later. The rest is just grabbed from storage as they're needed
Å Marlon G
Å Marlon G2y ago
So, just for a practical example: Say i wanted a CMS where clicking a button added a new page to the tree structure. Clicking the button runs a script creating the new page and giving option of what type of page to create (blog post, e.g.), but the construction of the page is a separate JS file with the instructions of how the page should look like (images, heading, h1, h2, etc.). The button click runs the script addpage.js, which is importing script from blogpage.js And within blogpage.js all the different elements mentioned are there own variables, functions, whatever, waiting to be run when called upon. ... in the right ballpark?
Jochem
Jochem2y ago
yeah, pretty much
Å Marlon G
Å Marlon G2y ago
Cool! 🥳
Want results from more Discord servers?
Add your server