JavaScript Short Circuit Logic - javascript

After seeing some examples online, I've collected two different explanations:
Ex: var x = A || B;
If A exists and B does not, left side is returned.
If A exists and B exists , return right side (last evaluated value).
Based on that logic, I would assume that x would return: v.item(0).click(). But when testing it x first returned B then A, aka fired B then fired A as well. Why? (http://jsfiddle.net/nysteve/QHumL/59/)
HTML:
<div class="indeed-apply-button" onclick="alert('BOOM BUTTON');">boo</div>
<div class='view_job_link' onclick="alert('BOOM LINK');">boo</div>
JavaScript
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
var x = v.item(0).click() || i.item(0).click();
EDIT 1:02 PM 10/10/2013
Did not mention my true intentions, but based on the answer and discussion, my goal was essentially to convert the following piece of code into the JavaScript code I originally mentioned.
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
In the code above, how would you read if(v){v.item(0).click();} vs. the short-circuit?

Neither of your two descriptions are accurate.
var x = A || B;
What that does is:
Evaluate "A". Call the result VA.
If VA is not null, undefined, 0, NaN, false, or the empty string, then the value of the overall expression is VA and evaluation stops.
Evaluate "B". Call the result VB. That value, VB, is the value of the expression.
Your test code first tests the return value of calling the "click" function on the first element and then the second. Those functions both return undefined, so the subexpressions on both sides of the || are evaluated. That is, the first call gets VA and it's undefined, so that means that the other side will be evaluated too, and that'll be the value of the expression. (It's going to come out undefined.)
edit — OK now that you've added more to the answer, I think I see what you're up to.
In your actual code (or, I guess, the sample code that's closer to reality), you've got:
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
That means something quite different than:
var x = v.item(0).click() || i.item(0).click();
Note that in the if statement version, it's explicitly checking "v". A test like that will perform a "truthy/falsy" test on the value of "v". In this case, it's really checking to make sure that "v" isn't either null or undefined. In the || version, however, there's no such explicit test for the "goodness" of variable "v"; it's just used directly. (If it happens to be null there, that'd result in a runtime error.)
A version of the actual code using || and && is possible, but in my opinion the existing code is clearer. However, just for discussion purposes, you could replace the if version with:
v && (v.item(0).click(), true) || i && i.item(0).click();
Personally I think that looks kind-of ugly.

Related

Programming optional ignorance

In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.

Keep losing incremental variable within for loop

I've been fiddling with this for way too long and can't seem to get it working as it should.
The problem I'm having is that I'm losing the value of my incremental variable in a for loop, specifically when it goes in to the if statement that I have inside of it. Ideally i want to iterate through an array until I find the correct value, attach a variable to that value and use it outside of the for loop. This is the structure of the array I'm working with.
var dXId = [
{url:"url1", dId:"id1"},
{url:"url2", dId:"id2"},
{url:"url3", dId:"id3"}
];
And here is the loop that I'm running everything through:
for(i=0; i < dXId.length; i++) {
if (dXId[i].url == currentUrl){
var dataXuId = dXId[i].dId;
break;
}
}
The incremental 'i' variable always reverts back to 0 within the if statement. It's odd, the dXId[i].url comes up correctly, but the dXId[i].dId pulls the first entry and 'i' seems to be lost after that. I'm sure there is a very simple solution to this, but javascript is something that I just always seem to have trouble with.
You are setting dXId[i].url = currentUrl inside your for loop instead of comparing with '=='. That could be part of the problem.
EDIT
As suggested by Eric...
The == Operator is to loosely compare the value of things, and the === is to strictly compare the value and type of things.
Examples:
Given x=10;
x == '10' // true
x == 10 // true
x === '10' // false
x === 10 // true
You have mistake in your if syntax.. you are assigning value of currentUrl to variable dXId[i].url
if (dXId[i].url = currentUrl){
...
}
It should be changed to === to compare string values.
if (dXId[i].url === currentUrl){
...
}
After that, it works! Example also here: js fiddle
Thus, it is rather funny that JavaScript lets do such things in the first place: Assigning value to a variable in if block should definitely not be allowed.
For example consider the following snippet:
var foo = 1, // change to 0 and console.log will not be displayed
bar; // undefined
// Assigning value of foo to bar
if (bar = foo){
// Will print out 1
console.log("bar is: " + bar);
}
Will result to a printing following output to the console:
bar is: 1
The reason being that if (bar = foo){ is equals to if (1){ which allows program to continue inside the if block :) ... if value of 0 is used for foo, console.log will not be displayed. (This is the behaviour at least which I tested using google chrome.)
Example about this in js fiddle

Get a return value from arbitrary eval'd code

I have a requirement that the user can provide arbitrary statements which can be stored in a function and called later to get a return value. A simple example of this is that userInput might be
var x = 10;
x;
I would store this via
var callback = function() {
return eval(userInput);
}
and then running callback() returns 10 as expected.
However, I also need to support the case with an explicit return statement, ie userInput might be
var x = 10;
return x;
In this case the eval method above will fail with SyntaxError: return not in function. Instead I could store callback as
var callback = new Function(userInput);
My issue is that I would like to combine these two approaches according the rule 'get explicit return value otherwise get the result of the last executed statement'. In particular this can't be done with analysis of the code at callback creation time as the user could potentially do something odd like
if(envVar < 10)
return a;
b * 0.5;
which combines both.
Any thoughts on how to structure the creation of the callback function to accommodate these possible inputs? Unfortunately it is not possible to enforce one style or the other on the user.
UPDATE to answer some of the comments below.
One solution suggested is to search for a return token and choose between new Function and eval. This doesn't work for my last example, see http://jsfiddle.net/ZGb6z/2/ - out4 should be "no" but ends up being undefined as the last executed statement is not returned.
Another suggestion is to modify the user input to add an explicit return on the last line if one is not found. Unfortunately it's not possible to know which statement will be executed last. Consider
var x = 10;
switch(x) {
case 10:
100;
break;
default:
200;
break;
}
When called it should return 100, but it would take some serious analysis to determine where to put returns for arbitrary code.
Just use a try catch, manipulating the input will be very painful for you, and try catch can't really make your code any more obtuse at this point.
var failback = function () {
try {
return eval(userInput);
} catch (e) {
return Function(userInput);
}
};
What I would really suggest is investing in a parser, kind of like how Angular does it. That kind of thing would prevent your users from doing whatever the hell they want, introducing attack vectors, yadda, yadda, yadda.
Either manage your expectations or manage your user's expectations. eval and new Function() are not suitable for your requirements if you require mixed usage of explicit and non-explicit return statements in the same user-input. You will continue to find issues following either of these routes.
Simply searching for the word return is not sufficient either... var returning = true; or var a = 'return'; or /* return true */ true; will all throw false positives.
Managing your expectations: To do such a thing you require a form of lexer and parser, at which point you can do away with eval entirely and execute your own safe functions based on the parsed input. This is the best approach when execution of user input has to occur anyway as you can ensure that nothing gets executed you do not wish to permit. If you want to cover these sort of edge cases and permit strange user input then you must be prepared to increase the size and development time of your application. I have built a few applications executing user generated code and have always come to the conclusion this is the correct route to go down.
Managing your user's expectations: Provide a guide, tell them not to mix explicit returns with non-explicit returns, these are strange coding practices anyway. Better yet explicitly tell them to include or omit the return statement. There is no shame in asking your users to follow them, especially if it allows you to improve their experience elsewhere.
There I was thinking I'd only see problems like this at the code golf stack exchange :)
My solution is here: http://jsfiddle.net/hKq87/1
It essentially replaces the 'return' statement with an exception that has a special string prefixed to it. If we see that string, we know we are actually returning a value, and return it rather than re-raising the exception.
The reason I chose to throw an exception rather than replace the return statement with a function call was because it is hard to know where the JS code evaluated for the return really ends. It could be split across multiple lines, contain several special characters and may not even have the optional semi-colon at the end. So I concatenate a string to whatever the value being returned is and throw it, as the throw keyword doesn't require it's argument to be wrapped in parentheses.
In addition, throwing exceptions provides me a convenient way to immediately terminate execution of the code block, without halting other JS execution.
Here is the callback method:
var callback = function(userInput) {
var returned = undefined;
userInput = userInput.replace(/(^|[\(\\)[\]{};,\s])return(\s*[^\s;])?/gi, function(m, b, e){
return b + " throw '__RETURNED_VALUE'" +
(e !== undefined ? "+" + e : "");
});
try {
returned = eval(userInput);
} catch (e) {
if (e.indexOf("__RETURNED_VALUE") == 0) {
returned = e.substring("__RETURNED_VALUE".length) || undefined;
}
else {
throw e;
}
}
return returned;
}
The regex above accounts for variables that may end with the string "return", that we would not want to replace as it is not a return statement. It also allows for return statements within braces, without trailing semi-colons or at the very beginning/end.
One issue with the current method is that you can not use the (rare) comma operator in a return statement, or expect numerical values to be returned correctly. The last test case in the jsfiddle demonstrates this. An example from here:
//original
return 5 * 2 + 3, 22;
//modified
throw '__RETURNED_VALUE='+ 5 * 2 + 3, 22;
//apply * operator
throw '__RETURNED_VALUE='+ 10 + 3, 22;
//apply + operators
throw '__RETURNED_VALUE=103', 22;
//apply , operator
throw 22;
This problem can be avoided by completely eliminating the prefix '__RETURNED_VALUE=' and just replacing 'return' with 'throw'. However, this means that the code provided must run without throwing exceptions, which I thought to be a harder constraint than just crafting return statements to be simple (avoiding comma operators, non-parenthesized arithmetic, etc.). In addition, if a user ever creates a return statement that we can't handle with the current code, we conveniently throw an exception for it so it easily comes to our attention.
jsFiddle Demo
Lets assume your user can be a little smarter than the average bear. We are going to ask them to specifically provide an initial value and then a callback with an expression for that value.
The main benefit of doing this is that you avoid eval, and actually have a nice implementation that is re-usable as opposed to being subject to later refactoring.
This way also provides a separation of where the input comes from and where the examination comes from. Although the provided example only shows integer input, really it could be another call with absolutely no knowledge of the value aside that it needs to conform to the callback logic.
function expression(x,callback){
return callback(x);
}
out1.innerHTML = expression(8,function(x){
return x;
});
out2.innerHTML = expression(10,function(x){
return x;
});
out3.innerHTML = expression(10,function(x){
if(x === 10) return "yes"; "no";
});
out4.innerHTML = expression(8,function(x){
return x === 10 ? "yes" : "no";
});

Curious how others would create a fallback for this: som var = number 0 || false?

so, I came across a bug and thought it was interesting. Once I sat and thought about it for 5 seconds, it made sense but curious how one would get past it in the future.
so, I have some hashes set up in an obj. (snippet of code from a larger obj).
someBigObj : {
someObj : {
item1 : 0
item2: 1
item4: 2
item3: 3
}
}
So, I set it up this way because I need to reference an Array position that corresponds to data that is associated with those items.
So, if I happen to reference item1 -- look what we get.
var varReference = someBigObj.someObj['item1'] || false;
// which is equivalent to
var varReference = 0 || false;
see what happens there? that reference is 0. So varReference is always false. I actually want the number 0 in this case because I need to access an array element. I think stringing it is odd to me, because it is not a string, but rather an integer. How can I still use this fallback of || false, but actually get the number 0 to be seen as a valid value.
Note: I understand I can explicitly test etc.. just curious if there is a a shortcut or native js (that I am unaware of) that solves my solutions. figured something like would work but didn't.
Number(0) || false
additional note: I ended not putting a || false, as even if it it's not referenced correctly there is no error. So it doesn't actually matter, but I always like to have fallbacks so that is why I am curious.
If you want falsey values to pass your test, then the test probably needs to look explicitly for undefined, not just a falsey value.
var varReference = someBigObj.someObj['item1'] !== undefined ? someBigObj.someObj['item1'] : false;
Keep in mind that lots of legitimate values are falsey such as 0, "", null (and others).
You can use an inline if to check if your value is undefined explicity.
var varReference = (typeof(someBigObj.someObj['item1']) !== 'undefined') ? someBigObj.someObj['item1'] : false;
Instead of trying to look at the value in the property (and its falsiness, which fails you sometimes), you should check whether the property exists in the object with the in operator:
var varReference = 'item1' in someBigObj.someObj
? someBigObj.someObj['item1']
: false;
which can be simplified to
var varReference = 'item1' in someBigObj.someObj && someBigObj.someObj['item1'];

Coffeescript ternary if-statement wrong logic

I have a pretty much simple logic in a return function, but it doesn't work as expected. Of course I can make the code slightly longer and solve the issue, but I want it to be as small as possible.
Here is my code:
#Return title if exists or false otherwise
getPageTitleFromMainContent = (mainContent) ->
mainContent.find('#pageTitle') ?.length ?= false
if y = (getPageTitleFromMainContent $("#mainContent"))
y.css color:red
As you see, if it finds the #pageTitle in #mainContent, it should make it red. But the function doesn't return the #pageTitle if found, it returns .length.
From js2coffee.org I see that the code is compiled into:
var getPageTitleFromMainContent, y;
getPageTitleFromMainContent = function(mainContent) {
var _ref, _ref1;
return (_ref = mainContent.find('#pageTitle')) != null ? (_ref1 = _ref.length) != null ? **_ref1 : _ref.length = false : void 0;**
};
if (y = getPageTitleFromMainContent($("#mainContent"))) {
y.css({
color: red
});
}
And it should be _ref : _ref.length = false : void 0;, not _ref**1** : _ref.length = false : void 0; .
http://jsfiddle.net/X8VjJ/1/
Thank you!
if it finds the #pageTitle in #mainContent, it should make it red
You can accomplish this with the much simpler:
$('#mainContent #pageTitle').css(color: 'red')
Since, if it doesn't find #pageTitle in #mainContent, it will try to change the css of an empty set of elements -- a no-op.
The code as you've presented it doesn't really make sense. ?. is unnecessary, as the jQuery selector will not return null or undefined if it doesn't match; it will return an empty set of elements. So it will always be returning length, which will always be a number, so the assignment will never execute, since it depends on length returning null or undefined. Which is good, since you probably don't want to set the length of the elements to false.
Finally, this isn't the ternary if statement. CoffeeScript's ternary if statement looks like this: if foo then bar else baz.
Not sure that code makes sense. You're effectively trying to assign TO the length property, unless length is defined. If it is defined, it simply returns the length property. Looks like the code and behaviour is correct, but your understanding of the existential operator and return values is wrong. If you want to return the found element you probably need to disconnect it from the length check.
Maybe something like:
getPageTitleFromMainContent = (mainContent) ->
arr = mainContent.find('#pageTitle')
if arr.length then arr else false
As Ian explained in his more elegant answer, you do not need to use the existential operator on arr (assuming jquery), since it will always be an array of elements (with zero length if not found).

Categories

Resources