How to avoid short-circuited evaluation in JavaScript? - javascript

I need to execute both sides of an && statement, but this won't happen if the first part returns false. Example:
function doSomething(x) {
console.log(x);
}
function checkSomething(x) {
var not1 = x !== 1;
if (not1) doSomething(x);
return not1;
}
function checkAll() {
return checkSomething(1)
&& checkSomething(3)
&& checkSomething(6)
}
var allValid = checkAll(); // Logs nothing, returns false
The problem here is that doSomething(x) should log 3 and 6, but because checkSomething(1) returns false, the other checks won't be called. What is the easiest way to run all the checks and return the result?
I know I could save all the values in variables and check those subsequently, but that does not look very clean when I have a lot of checks. I am looking for alternatives.

Use a single &. That is a bitwise operator. It will execute all conditions and then return a bitwise sum of the results.
function checkAll() {
return checkSomething(1)
& checkSomething(2)
& checkSomething(3)
}

You can multiply the comparison result and cast it to boolean.
function checkSomething(x) {
var not1 = x !== 1;
if (not1) alert(x);
return not1;
}
function checkAll() {
return !!(checkSomething(1) * checkSomething(2) * checkSomething(3));
}
document.write(checkAll());
Or take some array method:
function checkAll() {
return [checkSomething(2), checkSomething(2), checkSomething(3)].every(Boolean);
}

Coming back to my own question 2,5 years later I can agree with the people in the comments on how bad this code is by being based on side effects and therefore violating the single responsibility principle.
I just want to provide a proper solution for people visiting this page with the same question.
function doSomething(x) {
console.log(x);
}
function checkSomething(x) {
return x !== 1;
}
var values = [1, 3, 6];
var validValues = values.filter(checkSomething); // -> [3, 6]
validValues.forEach(doSomething); // -> Logs 3 and 6
var allValid = validValues.length === values.length; // false
As you can see, the checkSomething function now only does one thing: check something. The doSomething logic runs separately after all the checks are done.
A function should always either do something or return something, not both. Of course there are exceptions to this, but it is a good rule of thumb. This makes the code more predictable, testable and understandable.
Now, if at some point I want to check if all values are valid without "doing something", I can actually do this...
var allValid = checkSomething(1) && checkSomething(3) && checkSomething(6);
...without having to worry about side effects.
Conclusion: You don't want to avoid short circuited evaluation

Related

Difficulty with Boolean and arrays in Javascript

Here, I am trying to write a code that takes a list of integers as a parameter and searches for the value 7. The function will return a boolean value representing true if 7 is in the list and false if it is not. This is what I have tried so far:
Could it be something with my else statement? Do I end it too soon? Or not soon enough?
You can simply use an array and use includes as per ECMA2016 like below:
if([2,5,7].includes(value)) {
return true;
}
return false;
or with list
var flag = false;
for(var i=0; i<arguments.length; i++)
{ if(arguments[i] == this) { flag = true; break; }}
return flag;
Javascript already has a function to do this. Array.prototype.includes(). You use it like this:
const containsSeven = list.includes(7)
If you are looking for something more complicated, like whether an item is an object and contains a particular key value pair for example, you can use Array.prototype.some()
Your declaration of the if statement is wrong. The else tag is on the wrong line. If you use else, it should come after the if-block.
But moving the else-block up, won't fix your function, because it will only return true if the first element in your array is a 7.
There are many good ways to do it, such as using higher order functions, but as it seems you are new to the language.
EDIT: Therefore, I would suggest one of the two simple ways below:
1) You could store the number of 7s found in the array in a for loop. Afterwards return false if the number of 7s is 0 or true if it the number is higher than 0
2) Another, much quicker way would be to return true in the for-loop when you encounter a 7 and after the for-loop just return false. Because a return statement exits the scope - which is your function - not only the for-loop would come to an end but also your function would return true much earlier.
For the second option, your function would look like this:
function find_value(list) {
for (let i = 0; i < list.length; i++) {
if(list[i] == 7) {
return true
}
}
return false
}
You can coerces to boolean the result of Array.prototype.find() which returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
Code:
const list1 = [4, 5, 6, 7, 8];
const list2 = [1, 2, 3, 4, 5];
const findTheNumber = (arr, num) => !!arr.find(n => n === num);
console.log(findTheNumber(list1, 7));
console.log(findTheNumber(list2, 7));
Try this way
function search(list , value){ // Value = 7;
return true ? list.indexOf(value) > -1 : false
}

Can forEach in JavaScript make a return? [duplicate]

This question already has answers here:
What does `return` keyword mean inside `forEach` function? [duplicate]
(2 answers)
Why does this forEach return undefined when using a return statement
(5 answers)
Closed 1 year ago.
I wonder if forEach in JavaScript can make a return, here is my code:
var a = [0, 1, 2, 3, 4];
function fn(array) {
array.forEach(function(item) {
if (item === 2) return false;
});
return true;
}
var ans = fn(a);
console.log(ans); // true
I want to find out if 2 is in my array, if so, return false, but it seems that the forEach function has looped the whole array and ignore return.
I wonder if I can get the answer I want with forEach ( I know I can get what I want using for(..))? dear friend, pls help me, with great thanks!
You can use indexOf instead https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
function fn(array) {
return (array.indexOf(2) === -1);
}
Also from the documentation for forEach - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Note: There is no way to stop or break a forEach() loop other than by
throwing an exception. If you need such behaviour, the .forEach()
method is the wrong tool, use a plain loop instead.
So, the return value cannot be used the way you are using it. However you could do a throw (which is not recommended unless you actually need an error to be raised there)
function fn(array) {
try {
array.forEach(function(item) {
if (item === 2) throw "2 found";
});
}
catch (e) {
return false;
}
return true;
}
In this case .indexOf() is probably what you want, but there's also .some() when a simple equality comparison is too simple:
var ans = a.some(function(value) { return value === 2; });
The .some() function returns true if the callback returns true for any element. (The function returns as soon as the callback does return true, so it doesn't bother looking beyond the first match.)
You can usually use the .reduce() function as a more general iteration mechanism. If you wanted to count how many instances of 2 were in your array for example:
var twos = a.reduce(function(c, v) { if (v === 2) c += 1; return c; }, 0);
Others have mentioned .indexOf() and .some(). I thought I would add that a good old fashioned for loop gives you the absolute most iteration control because you control the iteration and your processing code is not embedded in a callback function.
While .indexOf() already does exactly what you need, this code just shows how you can directly return when using the old fashioned for loop. It is somehow out of favor these days, but is often still the best choice for better looping control.
function fn(array) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === 2) return false;
}
return true;
}
Using the for loop, you can iterate backwards (useful when removing items from the array during the iteration), you can insert items and correct the iteration index, you can immediately return, you can skip indexes, etc...
forEach returns undefined by specification. If you want to find out if a particular value is in an array, there is indexOf. For more complex problems, there is some, which allows a function to test the values and returns true the first time the function returns true, or false otherwise:
a.some(function(value){return value == 2})
Obviously a trivial case, but consider if you want to determine if the array contains any even numbers:
a.some(function(value){return !(value % 2)})
or as an ECMA2015 arrow function:
a.some(value => !(value % 2));
If you want to test if a particular value is repeated in an array, you can use lastIndexOf:
if (a.indexOf(value) != a.lastIndexOf(value) {
// value is repeated
}
or to test for any duplicates, again some or every will do the job:
var hasDupes = a.some(function(value, i, a) {
return a.lastIndexOf(value) != i;
});
An advantage of some and every is that they only process members of the array until the condition is met, then they exit whereas forEach will process all members regardless.
You said you want with forEach, so I modified your code:
function fn(array) {
var b = true;
array.forEach(function (item) {
if (item === 2) {
b = false;
}
});
return b;
}
var a = [0, 1, 2, 3, 4];
function fn(array, callback) {
var r = true;
array.forEach(function(item) {
if (item === 2) r = false;
});
callback(r);
}
fn(a, function(data) {
console.log(data) //prints false.
});
You can use callbacks as mentioned above to return the data you need. This is not same as the return statement but you will get the data.

How do you compare whether or not two functions behave the same in Javascript?

If I have 2 functions as vars, f1 and f2 - how can I determine whether or not the 2 functions will behave the same for all inputs? That is, they will return the same value for all inputs.
It is not going to be possible for arbitrary functions.
For example, consider the Collatz function (n becomes 3n+1 if n is odd or n/2 if n is even). It is hypothesised that all positive integers eventually end up in the cycle 4->2->1. Suppose that your functions are designed to indicate the cycle that the input reaches (or indicate if it never reaches a cycle). f1 might just print 4->2->1 but f2 might repeatedly apply the function until a cycle is detected (and have some other case for determining if it is not in a cycle). There are no currently known inputs where f1 and f2 give different answers but it is unknown whether such an input exists.
No, you cannot. The number of possible inputs to the given functions is infinite. So unless you know about some relation between them, a finite number of values will guarantee nothing.
One way is to write function which compares the outputs of some other functions which have been given the same input argument(s). Possible Input arguments can be pushed into an array to ease the process. Something like...
var func1 = function(inputValue) {
// return some stuff
};
var func2 = function(inputValue) {
// return some stuff
};
var inputArray = [/* some input values */];
function compare(array) {
var isSame = false;
for (var i = 0; i < array.length; i++) {
if (func1(array[i]) === func2(array[i]) {
isSame = true
} else {
return i
}
}
return isSame
}
var result = compare(inputArray);
if (typeof result === 'number') {
alert('Comparison failed at inputArray['+result+'] : ' + inputArray[result])
} else {
alert('Comparison success!')
}
The compare() fucntion returns two different types of result depending on the the if-condition. If all if-conditions are met we get a boolean (true), otherwise the for-loop stops and returns the index number where the comparison failed - which can then be used to point back to the input value that broke the chain.

Emulate/use Continuations in JavaScript?

I have a function that computes product of numbers in an array. The function should work like this
function prod (array){
//compute and return product
}
var arr = [1,2,3,0,4,5,0,6,7,8,0,9];
the function call:
prod(arr); //should return 6
prod(arr); //should return 20
prod(arr); //should return 336 (6*7*8)
prod(arr); //should return 9
prod(arr); //should return 0
prod(arr); //should return 0
prod(arr); //should return 0
In scheme, this is done with continuations, by storing previous state of the function (state of the function is captured just before its exit point) see this
So, in short, I want the javascript function return different values at different times with same parameter passed everytime.
JavaScript is a well designed language, so I hope there must be something which can emulate this. If there happens to be nothing in JS to do it, I do not mind to conclude with failure and move on. So, feel free to say its impossible.
Thanks.
JavaScript is not capable of supporting continuations: it lacks tail-calls.
Generally I would write this to use a "queue" of sorts, although CPS is also do-able (just have a finite stack :-) Note that other state can also be captured in the closure, making it an "explicit continuation" of sorts ... in a very gross sense.
Example using a closure and a queue:
function prodFactory (array){
// dupe array first if needed, is mutated below.
// function parameters are always locally scoped.
array.unshift(undefined) // so array.shift can be at start
// also, perhaps more closured state
var otherState
// just return the real function, yippee!
return function prod () {
array.shift()
// do stuff ... e.g. loop array.shift() and multiply
// set otherState ... eat an apple or a cookie
return stuff
}
}
var prod = prodFactory([1,2,3,0,4,5,0,6,7,8,0,9])
// array at "do stuff", at least until "do stuff" does more stuff
prod() // [1,2,3,0,4,5,0,6,7,8,0,9]
prod() // [2,3,0,4,5,0,6,7,8,0,9]
prod() // [3,0,4,5,0,6,7,8,0,9]
Happy coding.
"Finished implementation". Although this particular problem can avoid array mutation and just use an index: the same concepts apply. (Well, slightly different. With just an index the closed over variable would be altered, whereas with this approach an object is mutated.)
function prodFactory (array) {
array = array.slice(0)
return function prod () {
var p = 1
for (var n = array.shift(); n; n = array.shift()) {
p *= n
}
return p
}
}
var prod = prodFactory([1,2,3,0,4,5,0,6,7,8,0,9])
prod() // 6
prod() // 20
prod() // 336
You can give the function a property that will be remembered between calls:
function prod (array){
if (typeof prod.index === "undefined" || prod.currentArray != array) {
prod.currentArray = array;
prod.index = 0;
}
if (prod.index >= array.length)
return 0;
//compute and return product
var p = 1,
c;
while (prod.index < array.length) {
c = array[prod.index++];
if (c === 0)
return p;
p *= c;
}
return p;
}
I'm just guessing from your description of what should be returned that on an individual call to the function it should take the product of all of the numbers up to but not including the next zero or the end of the array. Calls after the end of the array should return 0? I may have the algorithm wrong for that, but you get the idea for what I'm suggesting to remember the function state between calls.
I've added a property to remember the current array being processed. As long as you keep passing the same array in to the function it will continue with the next elements, but if you pass a different array it will reset...
you can try something like
var index = 0;
function prod (array){
if(index < array.length){
var prod=1;
for(int i=index;i<array.length;i++){
if(array[i] != 0){
prod = prod * array[i];
}
else{
index = i+1;
return prod;
}
}
}
return 0;
}
this will update the global variable index everytime the function is called.
What you're looking for here are generators. As of 1.7, JavaScript supports them.

Check if array[4][3][7][3] is defined

When there is a single dimension array, it is easy to check whether it is defined, by either simple calling arr[6] which will return undefined if such property does not exist or calling typeof arr[6] === undefined.
The problem is, that in my case I have arr[5][1][6][2][5][3][7], where arr[5] can be non existent, or arr[5][1], etc. Which will naturally trigger error: TypeError: Cannot read property [..] One solution is to write many IF statements. However, is there any better solution, that'd simple allow me to check whether arr[5][1][6][2][5][3][7] is defined?
I can't think of anything better than:
var defined = false;
try {
defined = !!arr[5][1][6][2][5][3][7]
} catch(e)
{
// nothing
}
But seriously bad design.
Since this seemed like an interesting problem, I wrote this function to solve it in a nice an non-exceptional way :)
var deepCheck = function(arr, indexes) {
var level = arr;
while(indexes.length) {
var v = indexes.shift()
if(!level[v]) {
return false;
}
level = level[v];
}
return true;
};
Now say you have this:
arr[foo][bar][baz];
You would check it using...
deepCheck(arr, [foo, bar, baz]);
Maybe I should point out that I do kind of agree that if you indeed have very very long arrays like that, it does sound like a design issue.
By using a try/catch block you can check if the element can be accessed.
var x;
try {
x = arr[5][1][6][2][5][3][7];
} catch(TypeError)
{
// the element cannot be accessed
x = undefined;
}
Then it's easy enough to check if 'x' is defined or not using an if statement.
A pragmatic approach would be to break this problem down into its component parts; look at what data is known and the tools you have at hand.
So, what do we know - well we know the keys that we want to inspect, in the case of checking if arr[5][1][6][2][5][3][7] is defined. Now ask yourself, what tools do we have in JavaScript? To check if an Array index is defined we can compare against null, ie:
if (array[index] === null) {
return false
}
If we were to try and write this code, one of the first things that should come to mind is to simply walk through each key, in order: eg:
if (array[5] === null) {
return false;
} else if (array[5][1] === null) {
return false
} ...snip...
// Good news, it's defined!
return true
Obviously this approach can be improved, it requires a tonne of duplicated code to be written out, it's inflexible and not reusable. If you ever find yourself doing the same thing over and over, you probably have a good candidate for a loop construct. In order for a loop you need a variant, something that will change with each repetition - in the example above the variant is the right most element of the nested array we are inspecting. First, let's start by listing our variants out:
var variants = [ 5, 1, 6, 2, 5, 3, 7 ];
for (var i = 0; i < variants.length; i++) {
console.log("variant: " + variants[i]);
}
Where, do we go from here? Well things get a bit harder, you need to understand how Arrays are passed by reference in JavaScript and exploit that in the loop body; ultimately you may end up with something like this:
function arrayDimensionsExist(source, dimensions) {
var currentDepth = source;
for (var i = 0; i < dimensions.length; i++) {
var key = dimensions[i];
if (currentDepth[key] === null) {
return false;
} else {
currentDepth = source[key];
}
}
return true;
}
Put the code accessing it between try and catch. If it works, it works, if not you get a nice exception and you can react accordingly.
As a side note, I shudder to think of what prompted you to design your system like that...
There's no solution built-in to the language, but you could handle it with a function like this:
var verifyIndexes = function(target) {
var current = target;
for (i = 1; i < arguments.length; i++) {
if (arguments[i] in current) {
current = current[arguments[i]];
} else {
return false;
}
}
return true;
}
var myArray = [[[1, 2, 3], 4], 5];
console.log(verifyIndexes(myArray, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 3)); // false
console.log(verifyIndexes(myArray, 0, 1)); // true
console.log(verifyIndexes(myArray, 0, 2)); // false

Categories

Resources