Returning to Javascript after long break, forgot how to write a simple function

Hello again, dear Codecademy community.
I am trying to pick up where I left off a while ago with JS, and find that I’m uncertain about a lot of basics.
The Chore Door project asks me to

…create a function called isClicked that takes the parameter of door. Inside the isClicked() function, create a conditional that checks if the src property of door is equal to closedDoorPath. If the condition is truthy, return true. Otherwise, return false

I’ve come up with:

function isClicked (door) {
  if (door.src == closedDoorPath) {
    console.log("door was clicked");
    return true;
  } else {
    console.log("door was not clicked");
    return false;
  }
}

(log statements are solely for testing if it works, but I can’t seem to run the code yet, in this window?)
I believe it should work, but feels unnecessarily explicit and bloated.
Is it just how a pro would do it, or is there actually a shorter, more elegant way?

That seems fine to me.
If you really want to shorten it, you could do
const isClicked = door => (door.src == closedDoorPath);

2 Likes

It looks like it would always return undefined, no?
JavaScript has been letting go of all kinds of punctuation hasn’t it?
But the return keyword is also optional?

You don’t need the return in the function expression here
(since its only one line and there’s no {   } and no ; on the inside) .

So
const isClicked = door => (door.src == closedDoorPath);
does the same thing as
const isClicked = door => { return (door.src == closedDoorPath); };
or
function isClicked (door) { return (door.src == closedDoorPath); }

MDN reference

1 Like

Even the parens are superfluous. It would be helpful to inform the user about the advent of concise body arrow functions with a useful link to MDN.

2 Likes

That’s exactly what I was thinking of, but couldn’t remember - returning true or false using truthiness of an expression, but:

  1. I read on another learning site that a function with no return statement will return undefined.
    Is that a) old information b) true only under certain conditions or c) just wrong?

  2. writing the function like this, technically it doesn’t contain a conditional, does it?

  3. Declaring a function with the function keyword, no variable keyword like const is used, but a variable is nonetheless created. Will a variable created with the function keyword have the same properties as one created with const?

Thanks for the prompt, this also looks useful:

The statement is true for ES5 (standard) functions. Their syntax requires enclosing braces, parentheses around all parameters and an explicit return if there is anything being sent back to the caller. Given all the correct syntax, a function with no return or no return value will send undefined back to the caller. That is the only implicit return we can expect from these functions.

Now if you’ve been doing the reading you will by now have learned:

Arrow functions have:

  • implicit return of last expression in the function body
  • optional parens if there is only a single parameter
  • optional end braces if return is not used

Some of those points need further clarification but that can be gained by working in your sandbox with the examples given in your reading.

const double = x => x * 2;

Notice there are no parens, no braces, and no return keyword. Also, most notably, no function keyword, which has ramifications.

function has:

  • a this object bound to its own scope
  • an arguments object bound to the parameters
  • a declaration form and an expression form

Arrow functions have none of the above. They must be written as expressions; arguments are parsed using the rest operator and we avoid of the use of this since it upsets the purity of the function by interacting with outside objects.

The operative word here is, ‘declaring’. We spoke of the two forms, and declaration is the one that is not treated as an expression, specifically, but may still be inferred to be an expression and used as such. Consider the following two functions:

function foo (bar) {
    return bar;
}

function bar (foo) {
    return foo;
}

We come now onto the subject of scope, which is the localized environment where an object is declared (a function is an object). If it appears muddy, feel free to gloss over:

In JavaScript, declared functions are hoisted as an encapsulated object, meaning in its entirety. We can call a declared function well before it actually appears in the code base. JS makes two passes over script, and in the first pass it handles all the hoisting of declared objects (essentially loading up the call stack, but don’t give this another thought, just now) and in the second pass it begins winding down the stack through all the function calls it has collated. In other words, the script runs from end to end. All the declared functions could just as easily be at the bottom of the code base as at the top. When they are called, they exist in executable form in memory.

Variables, once we isolate out the declared function names, which are also variables, are also hoisted, but not as complete objects, but only as reference objects. The values they point to are not hoisted. That is why we cannot poll a variable before it is declared.

Function expressions fall into that category. Their function body is not hoisted, and therefore we cannot call them until after they appear in the code base.

Here it gets interesting. A declared function has no defenses. It can be overwritten and even have its name redeclared, and given how loose JS is with data types, that means changing its type is totally on the table. This is the one argument I have against using them in the global namespace. They are too vulnerable. Inside other functions? Not a problem, they are safe there. I use this technique alot.

Giving a reference absolute status makes it indestructible. That variable in its own scope can never be mutated so using it to declare function expressions is hands down, the surest way to prevent those objects from ever being corrupted or removed. It is for this purpose that the const declaration keyword came into being.

If perhaps I’m tying things in knots, here, let’s accept that declared functions and function expressions that use the function keyword behave exactly the same, only the latter is not hoisted. Let’s also accept that apart from the simplification of syntax and associated objects, arrow functions behave like normal functions.

Going forward, just keep in mind the rule mentioned above, don’t use function declarations in global scope. Make it a rule that you keep and enforce in all your code creations. The business about hoisting is really not all that important, and one that I don’t see any advantage worth exploiting. Of course there are edge cases in everything; just saying.

1 Like
function foo (bar) {
    return bar;
}

function bar (foo) {
    return foo;
}

Given the above TL; DR, it makes sense to bear this out in a new post since I obviously did not get into it, above. Sorry about that.

In global scope, both foo() and bar() are hoisted as declared functions. In their own scopes, the parameters are hoisted as variables. There will be no conflict as regards the overlapping names. They are in different scopes.

Now let’s say that somewhere in the code we end up declaring a variable, foo. What will happen? We already know… the function will be gone.

const foo = function (bar) {
    return bar;
}
// and,
const foo = bar => bar;

solve that problem since neither can be destroyed or mutated.

Just how simple a function is will play a factor in whether to use the ES5 syntax, or the arrow syntax. One suggests don’t wrestle busy functions into arrow functions; just use the old syntax and call it a day. When faced with really simple functions? Well that’s a no-brainer.

Bottom line, arrow functions are not meant to replace standard functions, just permit us to simplify and write functional code when the situation allows. Don’t throw away the baby with the bath water.

One last point that also didn’t get covered above,

declaration is the one that is not treated as an expression, specifically, but may still be inferred to be an expression and used as such.

We cannot go fully into explaining this until the subject of Higher Order Functions comes up, since that is where the inference is drawn. Functions are deemed, first class objects in JS. What this means in simple terms is that a function can take another function as an argument and/or may return a function object to the caller. Whether we invoke the function in the argument, or pass only a reference, we are treating the function as an expression.

For sure, dive into the subject of expressions and convince yourself of the importance of understanding them intimately given their prevalence in everything coding. In JS, as in many other languages, expressions are values. Look that one up, and happy reading!

2 Likes

While I’m still reading up, I stumbled upon this, and it seems to fit the topic perfectly: :smile: