I am new to Javascript and have noticed that statements have values:
> x = 1
<- 1
> if (false) {
x=1;
}
else { x=2 };
<- 2
Could somebody explain why statements have values what they are used for in real applications, since functions need to return values explicitly via return.
Is this related to the notion of completions, which are associated with values, irrespective of their type (Normal or Abrupt) ?
Normal completion values primarily come up in user code via eval, though even then it's not super common. The return value of eval is the final completion value of the executed statements. Since eval executes a list of statements, when you run eval("4") === 4 for instance, you're not evaluating an expression for a value specifically, automatic-semicolon-insertion is kicking in, so you're actually running eval("4;") and then getting the completion value of that statement.
In the future, completion-value semantics will also likely affect the do expression proposal which would allow for code like
const value = do {
if (false) {
1;
} else {
2;
}
};
value === 2;
You could almost look at your examples as a nice side-effect of the general completion value semantics in the language, as well. When you throw or return from a function, the spec language itself for instance, still traverses the whole function. Returning or throwing essentially says "the completion value is this value" with the type "return" or "throw". So if you had
function fn()
if (false) {
return 1;
} else {
2;
}
}
one branch of the "if" produces an abrupt completion with value 1, and the other produces a normal completion with a value 2.
When execution (from the spec standpoint), gets to the end of the function itself, it will say "is this a return/throw, if so, propagate it to the caller of the function. If it is a normal completion, it will just discard the value and return undefined.
So really, the fact that there is a completion value is exactly the same as having a return value or throwing an exception value, from the standpoint of the spec, it just happens to discard the value in most cases if it is a non-abrupt completion.
Related
I just learned about the ternary operator but it is not functioning like I expected. If find it really confusing. I get an error in the console over and over again, and I don't understand why.
A normal function gives me undefined, which is fine, but the ternary operator gives me a "not defined" error, but why?
Ternary Operator
var experiencePoints = winBattle() ? 10 : 1;
Error
VM363:1 Uncaught ReferenceError: winBattle is not defined
My function
function experiencePoints() {
if (winBattle()) {
return 10;
} else {
return 1;
}
}
And it gives:
undefined
I want to get undefined just like the normal function gives.
The error is not because you used the ternary operator.
The message is telling you that JavaScript cannot find a function named "winBattle()" anywhere in your code - or at least, not within the current scope.
As we will see in this demonstration, if you declare such a function, and make it return a simple boolean "true" value (just for example), then the error does not occur:
var experiencePoints = winBattle() ? 10 : 1;
console.log(experiencePoints);
function winBattle()
{
//I assume here you would have some logic to calculate the winner of the battle, and then return true or false depending on who won.
return true;
}
You will need to check the rest of your code, and either
a) create the function, if it doesn't exist
or
b) make it accessible from the scope where you are calling it. If you need help with this task, you will have to show us the rest of your code.
Here is some background information:
I think you may have mistaken the undefined you're seeing as the result of executing the "experiencePoints" function. It is not. It is simply the result of creating that function via the console. The console always shows the result of the line you just created, which in this case is nothing, because you're just declaring a function, not running anything which produces output. If you included that function in a web page you would not see such a message. You have never actually run that function. If you did (by writing experiencePoints();) you would almost certainly see the same error relating to winBattle(), since at the time you run the function, winBattle() does not exist.
The difference between that and your ternary operator code is that this line of code is not within a function, and is therefore executed immediately.
The two are not the same: the function experiencePoints only executes when it is called, but you are not calling it. Instead you enter the function definition itself which does not return anything, and so you see undefined in the console.
The variable assignment with the ternary operator is executed on-the-spot (it is not a function definition), and so winBattle must exist at that very moment. Apparently it doesn't, and so you get an error. If you would just do this:
var a = Math.random() > 0.5 ? 10 : 1
You will not get an error, because Math.random is defined. Also you will see undefined in the console, which is normal for a statement, like var.
Coming back to the function experiencePoints: you may wonder why you don't get the same error about winBattle there. It is because the function is not executed yet.
Until you actually call it, you still have time to define winBattle. If however you decide to call it without first defining winBattle, you will get that same error.
Now you can of course use a ternary operator in a function -- that would be a fair comparison. You can choose between several syntaxes. Here are two:
function experiencePoints {
return winBattle() ? 10 : 1;
}
or as arrow function with expression syntax:
var experiencePoints = () => winBattle() ? 10 : 1;
Again, here you would only get an error about winBattle when you call the function.
var a = 1;
function myFunction() {
++a;
return true;
}
// Alert pops up.
if (myFunction() && a === 2) {
alert("Hello, world!");
}
// Alert does not pop up.
if (a === 3 && myFunction()) {
alert("Hello, universe!");
}
https://jsfiddle.net/3oda22e4/6/
myFunction increments a variable and returns something. If I use a function like that in an if statement that contains the variable which it increments, the condition would be order-dependent.
Is it good or bad practice to do this, and why?
Conditions are order-dependent whether you change the variables used in the condition or not. The two if statements that you used as an example are different and will be different whether you use myFunction() or not. They are equivalent to:
if (myFunction()) {
if (a === 2) {
alert("Hello, world!")
}
}
// Alert does not pop up.
if (a === 3) {
if (myFunction()) {
alert("Hello, universe!")
}
}
In my opinion, the bad practice in your code is not the fact that you change the condition's operands value inside the condition, but the fact that your application state is exposed and manipulated inside a function that does not even accept this state changing variable as a parameter. We usually try to isolate the functions from the code outside their scope and use their return value to affect the rest of the code. Global variables are 90% of the time a bad idea and as your code base gets larger and larger they tend to create problems that are difficult to trace, debug and solve.
It's bad practice, for the following reasons:
The code is far less readable than well-constructed code. This is very important if the code is later examined by a third party.
If myfunction is changed later, the code flow is completely unpredictable, and might require a major documentation update.
Small and simple changes can have drastic effects on the execution of the code.
It looks amateur.
If you have to ask, it's hardly a good practice. Yes, it's a bad practice for exactly the reason you mentioned: changing the order of operands of a logical operation should not affect the outcome, and therefore side effects in conditions should generally be avoided. Especially when they are hidden in a function.
Whether the function is pure (only reads state and does some logic) or whether it mutates state should be obvious from its name. You have several options to fix this code:
put the function call before the if:
function tryChangeA() {
a++;
return true;
}
var ok = tryChangeA();
if (ok && a == 2) … // alternatively: if (a == 2 && ok)
make the mutation explicit inside the if:
function testSomething(val) {
return true;
}
if (testSomething(++a) && a == 2) …
put the logic inside the called function:
function changeAndTest() {
a++;
return a == 2;
}
if (changeAndTest()) …
MyFunction violates a principle called Tell, Don't Ask.
MyFunction changes the state of something, thus making it a command. If MyFunction succeeds or somehow fails to increment a, it shouldn't return true or false. It was given a job and it must either try to succeed or if it finds that job is impossible at the moment, it should throw an exception.
In the predicate of an if statement, MyFunction is used as a query.
Generally speaking, queries should not exhibit side-effects (i.e. not changing things that can be observed). A good query can be treated like a calculation in that for the same inputs, it should produce the same outputs (sometimes described as being "idempotent").
It's also important to know that these are guidelines to help you and others reason about the code. Code that can cause confusion, will. Confusion about code is a hatchery for bugs.
There are good patterns like the Trier-Doer pattern which can be used like your code example, but everyone reading it must understand what's happening though names and structure.
The code presents more then one bad practice actually:
var a = 1;
function myFunction() {
++a; // 1
return true;
}
if (myFunction() && a === 2) { // 2, 3, 4
alert("Hello, world!")
}
if (a === 3 && myFunction()) { // 2, 3, 4
alert("Hello, universe!")
}
Mutates a variable in a different scope. This may or may not be a problem, but usually it is.
Calls a function inside an if statement condition.
This do not cause problems in itself, but it's not really clean.
It's a better practice to assign the result of that function to a variable, possibly with a descriptive name. This will help whoever reads the code to understand what exactly you want to check inside that if statement. By the way, the function always return true.
Uses some magic numbers.
Imagine someone else reading that code, and it is part of a large codebase. What those numbers mean? A better solution would be to replace them with well named constants.
If you want to support more messages, you need to add more conditions.
A better approach would be to make this configurable.
I would rewrite the code as follows:
const ALERT_CONDITIONS = { // 4
WORLD_MENACE: 2,
UNIVERSE_MENACE: 3,
};
const alertsList = [
{
message: 'Hello world',
condition: ALERT_CONDITIONS.WORLD_MENACE,
},
{
message: 'Hello universe',
condition: ALERT_CONDITIONS.UNIVERSE_MENACE,
},
];
class AlertManager {
constructor(config, defaultMessage) {
this.counter = 0; // 1
this.config = config; // 2
this.defaultMessage = defaultMessage;
}
incrementCounter() {
this.counter++;
}
showAlert() {
this.incrementCounter();
let customMessageBroadcasted = false;
this.config.forEach(entry => { //2
if (entry.condition === this.counter) {
console.log(entry.message);
customMessageBroadcasted = true; // 3
}
});
if (!customMessageBroadcasted) {
console.log(this.defaultMessage)
}
}
}
const alertManager = new AlertManager(alertsList, 'Nothing to alert');
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
A class with a precise function, that use its own internal state, instead of a bunch of functions that rely on some variable that could be located anywhere. Whether to use a class or not, it's a matter of choice. It could be done in a different way.
Uses a configuration. That means that would you want to add more messages, you don't have to touch the code at all. For example, imagine that configuration coming from a database.
As you may notice, this mutates a variable in the outer scope of the function, but in this case it does not cause any issue.
Uses constants with a clear name. (well, it could be better, but bear with me given the example).
A function that changes stuff. What is the world coming too? This function must change stuff and return different values each time its called.
Consider the dealCard function for a deck of playing cards. it deals the cards 1-52. Each time it is called it should return a different value.
function dealCard() {
++a;
return cards(a);
}
/* we'll just assume the array cards is shuffled */
/* for the sake of brevity we'll assume the deck is infinite and doesn't loop at 52*/
I've been doing Project Euler 'cause reasons. At one point, I found myself wanting to compare a value with the result of a function. I've since selected a different solution, but it's left me curious. How would this work? If I were to do something like:
//javascript
if x == mathyFunction(10){
//do this
}
function mathyFunction(y){
if(y>0){
mathyFunction(y-1);
return y;
} else {
return y;
}
}
I'm aware that this isn't tail recursive or anything fancy, I'm mostly just curious how the logic works behind this.
How would the computer interpret it? Would it return true if any one of the values == x or would it only return true if all the values == x. Experimentation has left me guessing, though I'll keep digging.
You didn't specify which language you're asking about, but assuming the usual semantics of the return statement, a function can't return more than once. So if by "return all values individually", you meant something like this:
function f() {
return 1;
return 2;
...
}
Then everything after the first return is just dead code and it's the same as if the return 1 was the only return statement in there. A function call has exactly one value and that value is what you're comparing against.
If you meant that mathyFunction returns a list or other collection object, which contains the values between x and y, then x will be compared to that list. Again the semantics will depend on the language, but in most languages comparing a number to a list will either be a type error or just false.
If by returning the values individually you were referring to a yield statement (like C#'s yield return or Python's yield), then the result of the function is going to be some kind of iterator object and the same thing as in the previous paragraph applies.
I'm trying to refresh some Javascript knowledge for an upcoming interview. I was reading a blog that says
"The delete operator returns true if the delete was successful."
and then shows an example of it in use:
var christmasList = {mike:"Book", jason:"sweater" }
delete christmasList.mike; // deletes the mike property
In that example it looks like delete is used in the manner that a void function (in the general programming sense -- I know that JS doesn't require declarations like void) would be.
Can someone explain to me, or give me a link to, the documentation that explains how JS functions can act with different return values, and does such require separate implementations for each return value?
You can check the Delete operator which says:
If desc.[[Configurable]] is true, then
Remove the own property with name P from O.
Return true.
Note that delete only works for properties of objects. Also a good read:- JavaScript Delete() Only Affects The Referenced Object Regardless Of Prototype Chain
In that example it looks like delete is used in the manner that a void function
The delete operator is not a function, it is an operator. It deals with properties of objects, not their values.
Functions are something else, but since you asked:
Can someone explain to me how JS functions can act with different return values
JavaScript is loosely typed. Functions don't care about the types of values unless they need to, and (most of the time) conversion between types is handled by operators.
If a function needs to are about what it is operating on, then it has to examine the value to see what it is.
For example:
function myFunction(myArgument) {
if (typeof myArgument === "function") {
return myArgument();
} else {
return myArgument;
}
}
A function can return any value it likes.
function string_or_number() {
if (Math.random() > 0.5) {
return 1;
} else {
return "1";
}
}
Strongly typed languages care about what type of value a function returns and what type of value is passed into an argument.
Loosely typed ones simply don't. There's nothing special about it from the point of view of someone using the language.
It shunts most of the complexity about having to care about types to the compiler author instead of the user of the compiler (who just has to care that, if a function is designed to do something to a duck, what they pass is sufficiently like a duck to not break the function).
As others note, delete is technically an operator and not a function; for our immediate concerns, however, the difference is academic, as the operator's behavior is the same as that of many functions used for their side effects (which is to say, void functions). Both the rule of the language and the conventions of their use are simple.
Rule
All functions provide a return value; if no return statement is reached, this will be undefined
Conventions
Since we always get a return value, we can take advantage of it to improve our programs. There are two conventions; which one should be used depends on the use case.
Return a boolean, signalling success or failure
Return some object being operated on
Option 2 is most useful for methods on objects: if our method changes the state of the object and then returns the object, we can bundle several changes into a single line of method calls: object.change1().change2().change3(newVal);
Option 1 is most useful when we want to use the success or failure of an operation to determine program flow; maybe we want to throw an exception if the property was not deleted but continue normally if it was. Then we can use if (delete object.property) to attempt to delete the property and branch into success/failure cases immediately.
From the MDN on the delete operator:
Throws in strict mode if the property is an own non-configurable property (returns false in non-strict). Returns true in all other cases.
I can't make it simpler than that. Aside from a small example:
alert(delete window.window)
alert(delete window.foobar)
alert(delete window.alert)
Javascript functions always return ambigious values. One function can return boolean, string, object, array or HTMLElement.
There is no fixed type.
function masterSwitch(input) {
switch(input) {
case 0 : return "Hello";
case 1 : return 0xdead;
case 2 : return 0.00042;
case 3 : return document.createElement("DIV");
case 4 : return true;
case 5 : return window;
case 6 : return this;
case 7 : return null;
default:window.alert("Please specify input from 0 to 8");
}
}
<input type="text" id="output"> <SELECT onchange="document.getElementById('output').value = typeof masterSwitch(this.selectedIndex);">
<option>string</option>
<option>int</option>
<option>float</option>
<option>HTMLElement</option>
<option>boolean</option>
<option>window</option>
<option>this</option>
<option>null</option>
</select>
How does a return statement inside a try/catch block work?
function example() {
try {
return true;
}
finally {
return false;
}
}
I'm expecting the output of this function to be true, but instead it is false!
Finally always executes. That's what it's for, which means its return value gets used in your case.
You'll want to change your code so it's more like this:
function example() {
var returnState = false; // initialization value is really up to the design
try {
returnState = true;
}
catch {
returnState = false;
}
finally {
return returnState;
}
}
Generally speaking you never want to have more than one return statement in a function, things like this are why.
According to ECMA-262 (5ed, December 2009), in pp. 96:
The production TryStatement : try Block Finally is evaluated as follows:
Let B be the result of evaluating Block.
Let F be the result of evaluating Finally.
If F.type is normal, return B.
Return F.
And from pp. 36:
The Completion type is used to explain the behaviour of statements (break, continue, return and throw) that perform nonlocal transfers of control. Values of the Completion type are triples of the form (type, value, target), where type is one of normal, break, continue, return, or throw, value is any ECMAScript language value or empty, and target is any ECMAScript identifier or empty.
It's clear that return false would set completion type of finally as return, which cause try ... finally to do 4. Return F.
When you use finally, any code within that block fires before the method exits. Because you're using a return in the finally block, it calls return false and overrides the previous return true in the try block.
(Terminology might not be quite right.)
The finally block rewrites try block return (figuratively speaking).
Just wanted to point out, that if you return something from finally, then it will be returned from the function. But if in finally there is no 'return' word - it will be returned the value from try block;
function example() {
try {
return true;
}
finally {
console.log('finally')
}
}
console.log(example());
// -> finally
// -> true
So -finally- return rewrites the return of -try- return.
I'm gonna give a slightly different answer here: Yes, both the try and finally block get executed, and finally takes precedence over the actual "return" value for a function. However, these return values aren't always used in your code.
Here's why:
The example below will use res.send() from Express.js, which creates a HTTP response and dispatches it.
Your try and finally block will both execute this function like so:
try {
// Get DB records etc.
return res.send('try');
} catch(e) {
// log errors
} finally {
return res.send('finally');
}
This code will show the string try in your browser. ALSO, the example will show an error in your console. The res.send() function is called twice. This will happen with anything that is a function. The try-catch-finally block will obfuscate this fact to the untrained eye, because (personally) I only associate return values with function-scopes.
Imho your best bet is to never use return inside a finally block. It will overcomplicate your code and potentially mask errors.
In fact, there's a default code inspection rule set-up in PHPStorm that gives a "Warning" for this:
https://www.jetbrains.com/help/phpstorm/javascript-and-typescript-return-inside-finally-block.html
So what do you use finally for?
I would use finally only to clean-up stuff. Anything that is not critical for the return value of a function.
It may make sense if you think about it, because when you depend on a line of code under finally, you are assuming that there could be errors in try or catch. But those last 2 are the actual building blocks of error handling. Just use a return in try and catch instead.
why you are getting false is you returned in a finally block. finally block should execute always. so your return true changes to return false
function example() {
try {
return true;
}
catch {
return false;
}
}
Returning from a finally-block
If the finally-block returns a value, this value becomes the return
value of the entire try-catch-finally statement, regardless of any
return statements in the try and catch-blocks
Reference: developer.mozilla.org
As far as I know, the finally block always executes, irrespective of whether you have a return statement inside try or not. Ergo, you get the value returned by the return statement inside finally block.
I tested this with Firefox 3.6.10 and Chrome 6.0.472.63 both in Ubuntu. It is possible that this code may behave differently in other browsers.
Finally is supposed to ALWAYS run at the end of a try catch block so that (by specification) is why you are getting false returned. Keep in mind that it is entirely possible that different browsers have different implementations.