I've starting to dig my teeth into backbone and when working with a router function creating and destroying views I came across this little snippet, which didn't quite make sense to me as I've always assumed these sorts of operators only work in conditional statements,
this.view && this.view.remove();
It was inside of a method attached to the router which seems to work like a charm, but I'm always weary of voodoo code that doesn't sit well with me.
Heres the full method
loadView : function(view) {
this.view && this.view.remove();
this.view = view;
}
Would love to understand this a bit better, hope its not too silly to ask.
Cheers.
In JavaScript:
this.view && this.view.remove();
is equivalent to
this.view ? this.view.remove() : this.view;
The righthand side is only executed if the lefthand side is truthy. If the value of the expression is ignored and the lefthand side has no side-effects (as in this case), then it's also equivalent to this:
if (this.view) {
this.view.remove();
}
So, in this specific case if there is an existing view, then it is removed. Note that the value of this expression is not necessarily a boolean (unlike in many other languages); it's whatever is returned by remove. However, this value is ignored, so it's not actually pertinent.
The operator && in javascript evaluates the first expression, if it is falsy it is returned, if it is truthy the second expression is evaluated and returned.
For || it is the other way round: the first expression is evaluated, if it is truthy it is returned, else the second expression is evaluated and returned.
Related
I'm new to Javascript, CSS, HTML, and jQuery, and came across this line of code that uses the condition ? if true : if false statement, and I'm trying to understand it. What would it's equivalent if() {} else {} statement look like? This is the line of code:
$('.app-container').css('background', this.background ? `url(${this.background.get('Href')})` : `url(${DefaultImage.Background}`);
Thanks for any explanation :)
You need to expand the second parameter that was passed to url() to an if, else as that is evaluated first:
if (this.background)
bgurl = `url(${this.background.get('Href')})`
else
bgurl = `url(${DefaultImage.Background})`
$('.app-container').css('background', bgurl);
If you're looking for exactly what this would look like with a traditional if-else:
if (this.background)
$('.app-container').css('background', `url(${this.background.get('Href')})`);
else
$('.app-container').css('background',`url(${DefaultImage.Background}`);
In javascript the ternary operator follows this basic premise:
(condition) ? (what will happen if condition evaluates to true) : (what will happen if condition evaluates to false)
Sometimes they can be difficult to decipher but in the right situation (like this one) they can save you from writing 'extra' code.
I ran into this piece of code:
<a ng-click= "item.statusId !== itemStatus.in || transfer()">
I guess we can generalize as:
<element ng-click = "someVar !== someValue || doStuff()">
I then found this article on short circuits and another more focused one once I knew what they are called. However, I still don't get it.
Does it basically work on the principle of an OR statement ending evaluation if the first statement evaluates to true? So if the first statement is true, end evaluation, if it's false, run the function in the second half of the OR statement? (This is the main question I am asking, everything else is extra).
I guess that part I don't get is whether the compiler interprets this code differently or it still evaluates to false and just runs the function. Not even sure how to phrase Q.
Does it basically work on the principle of an OR statement ending evaluation if the first statement evaluates to true? So if the first statement is true, end evaluation, if it's false, run the function in the second half of the OR statement?
It's effectively shorthand for an if statement, and you intuited correctly why it works. For more details on short-circuit evaluation in JavaScript, see this Stack Overflow question.
That code is equivalent to:
//Note the intentional and explicit use of `== false` to mean falsy (NOT `=== false` to indicate strict equality test for false)
if( (item.statusId !== itemStatus.in) == false ) {
transfer();
}
It is an interesting means of executing a function only when a condition is falsy.
There are many different examples of this around on StackOverflow, and is not specific to AngularJS.
I opened a js file that I wrote a while back and although it's working, I thought I spotted an error. (JS is not my primary language)
I had this:
if( myvar = fieldval.match(mypattern))
{
//Do Stuff
}
So I think I get it. Is this a correct statement?:
A javascript assignment operation evaluates to the value being assigned.
I tested on w3schools
<script type="text/javascript">
var str="The rain in SPAIN stays mainly in the plain";
var patt1=/ain/gi;
var test
document.write(test=str.match(patt1));
</script>
and it writes "ain,AIN,ain,ain" where I might have expected it to write "true" or not to write at all because boolean true is not a string. Is my line of thought and then ultimate conclusion correct. (I ask about my line of thought on this because I do not have a lot of formal CS training.)
It is a correct statement. The new value of myvar is tested:
if ( myvar = fieldval.match(mypattern) )
When the String.match method cannot find a match, it returns null. !!null === false, so the if-block is not evaluated. When any non-empty match is found, the condition is true, and the block is evaluated.
In this case, it is very likely that the if-statement is correct, and that the following is intended:
if ( (myvar = fieldval.match(mypattern)) !== null )
Rob W is correct, however it's extremely poor practice to put an assignment in an if statement like that. In the future, anyone coming along (including yourself) will scratch their head at that statement to determine if that's what you really meant.
I highly recommend Douglas Crockford's talk: http://www.youtube.com/watch?v=taaEzHI9xyY It'll make anyone (Js dev or not) a better developer for watching it because you'll consider the implications of your coding style and what future maintainers might assume.
match returns an array of matching values, not boolean. Use test instead.
The function string.match() returns an array of matches, or null if no matches are found. The code works because null evaluates to false in an if statement, while an array evaluates to true.
So indeed, the result of str.match is stored in myvar and then myvar is evaluated as boolean. It works as expected.
I've just been looking at the _.isEqual function of Underscore.js and a section of the code goes something like this:
if (a === b) return true;
if (typeof a !== typeof b) return false;
if (a == b) return true;
I'm just wondering if there's any case where the third statement could be reached and evaluate to true?
Edit: Just to be clear, this isn't my own code I'm talking about, I'm reading the source of Underscore, in particular, this line and I was curious about why they're doing that.
I've just been browsing through the Underscore repo and came across a short discussion where someone asked the exact same thing, and it looks like it is actually unnecessary.
Following the algorithm defined by the ECMAScript Language Specification in section 11.9.6 and section 11.9.3 seems to show that no pair of values should return true in the above case.
So, in short, no, that situation is not possible.
The only situation where == and === react unexpectedly is when comparing a literal string ("123") to a constructed string (new String("123")), which would fail the first test.
However, on the second test it gets caught because the constructed string has the type object, but the literal has the type string.
Based on that, I'd say no, the third statement can never be reached, and evaluate to true.
When you use the == operator and the expressions are of different types, JavaScript will generally convert the two into the same type before comparing.
For example, this can happen with null and undefined. null == undefined is true, even though null === undefined is false. However typeof null is "object", while typeof undefined is "undefined". So, in this case you should return false on the second statement.
You can read all the details in the spec (section 11.9.3), it is very involved:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
My initial guess was that it was to work around a broken browser implementation.
However after digging into the git logs for that file it looks like the corresponding line was in the very first underscore.js checkin. (I'm not gonna hunt in the parent documentcloud core.js repo...) You can see it at line 334 of https://github.com/documentcloud/underscore/commit/02ede85b539a89a44a71ce098f09a9553a3a6890 .
So now my guess is that its just cruft that got left in, never completely tested and never cleaned out.
I'm working on a script that accepts a settings object, but uses default values where settings are not provided.
I just wrote the following line of CoffeeScript:
iframe_width = settings?.iframe?.width? ? $iframe_body.width()
My intent, in plain English, is:
If the settings object is defined, and it defines a property iframe, and the iframe property defines a property width, then assign the value of the latter property to the variable iframe_width. Otherwise, assign the value returned by calling $iframe_body.width().
Does my CoffeeScript code reflect my intent, and is it the most effective way to express that? It seems awkward with all of the existential operators (?), so I wanted to put it out there for some feedback (the compiled JavaScript is very terse and cryptic, so it's hard to tell if should work as intended).
Also, I'm not sure whether there's any redundancy in using both the standard existential operator (?) and its accessor variant (?.) together.
Thanks!
Update:
The code above doesn't seem to work as expected; however, this does:
iframe_width = settings?.iframe?.width ? $iframe_body.width()
That makes sense, since I don't think the former code actually accesses the width property, but rather just checks for its existence (twice, even?). In this code, I removed the ? just after the width property, since I think that's redundant with the ? operator between the two expressions. Does that seem correct?
(Note: This answer was written before the question was updated. As the questioner realized, foo? ? bar isn't just redundant—it actually won't work, because foo? evaluates to true or false, and is therefore always non-null.)
You have two good options for simplifying this: One, you could replace the existential binary operator with an or:
iframe_width = settings?.iframe?.width? or $iframe_body.width()
Two, you could ditch the ? after width—it's redundant:
iframe_width = settings?.iframe?.width ? $iframe_body.width()
Now, you could do both if and only if iframe.width will never be 0 (since 0 or x is x). If you can be sure of that, go ahead and make it
iframe_width = settings?.iframe?.width or $iframe_body.width()