Are these lines of JavaScript code equivalent? - javascript

I've found this string in JavaScript code.
var c = (a.b !== null) ? a.b : null;
This is a shorthand of an if-else statement, however the value null is assigned if it is null. Isn't that ALWAYS equivalent to
var c = a.b
including all cases - exceptions, null, undefined, etc?
In another words, are these lines (always) equivalent?
var c = (a.b !== null) ? a.b : null;
-vs-
var c = a.b

No, they AREN'T NECESSARILY EQUAL always if b is a getter that updates a variable. It's bad practice to code this way though
var log = 0;
var a = {
get b() {
log++;
return log;
}
}
var c = (a.b !== null) ? a.b : null;
// outputs 2
console.log(c);
var log = 0;
var a = {
get b() {
log++;
return log;
}
}
var c = a.b;
// outputs 1
console.log(c);

These statements are logically equivalent.
That being said, and as mentioned in another answer, if a.b has side effects, the statements will not result in the same program state.
This could be readily obvious in the form of var c having a different value depending on which of these statements are executed, or more hidden, if a.b modifies something elsewhere in the program.
Refactoring
As refactoring has been discussed, I'll touch on it briefly. As the above has hopefully made obvious, directly refactoring would not be safe in all scenarios. However, I would still recommend a refactor of one kind or another.
The two possible situations as I see them are:
a.b has no side effects, direct refactoring is safe
a.b has hidden side effects. This represents very unclear, confusing,
and just downright bad code. It should be refactored so that all
changes happening during the statement are clear and obvious to a
reader (hopefully intuitively so, as well as supported by comments).

As #potatopeelings already pointed out, the two possible statements are not always equivalent, since one can write obscure code, which will have different results.
However, if I see a code, like
var c = (a.b !== null) ? a.b : null;
I will assume that the code's intention is
var c = a.b;
so I will change it to make the code prettier. If I will be negatively surprised, that is, the code does not pass the testing phases due to this change, then I will try to find the author of a.b with git blame.
So, my answer is, that the two statements are not equivalent, but should be equivalent in well-written code.

Well, actually not even
var c = (a !== null) ? a : null;
is guaranteed to be equivalent to
var c = a;
when a is resolved by a getter or an ES6 proxy handler on the global object.
Hence for instance, this assign to c the value 0:
Object.defineProperty(self, 'a', { get: function() { return c ^= 1; } });
var c = (a !== null) ? a : null;
console.log(c);
while this assigns to c the value 1:
Object.defineProperty(self, 'a', { get: function() { return c ^= 1; } });
var c = a;
console.log(c);

You're right, var c = a.b is exactly the same as var c = (a.b !== null) ? a.b : null;
My guess is the null in the ternary operator was meant to be anything except null, a default value if you will.

The reason for that confusingly odd syntax is because a.b might be an empty string OR undefined, and apparently an empty string is valid input.
Also, note: a.b might be a function.

Related

In Angular, what does the double pipe ('||') mean? [duplicate]

People often write this in order to specify default values:
var thing = this || that;
which is, AFAIK, the same thing as this:
var thing = !!this ? this : that;
What do you call the technique used to specify defaults in the first code block?
NOTE: I am not asking what a logical OR is called. I am asking what the alternative to ternary notation (as written in the first code block) is called.
I'd call:
var a = A || B;
conditional assignment, since it is effectively:
if (!!A) {
a = A;
} else {
a = B;
}
and it is a replacement for the conditional operator : ?
var a = A? A : B;
It might also be called "logical assignment" since it involves a logical OR expression, but it doesn't seem to fit with what it's doing.
As mentioned elsewhere it is a logical OR.
The evaluation in question is a short-circuit evaluation.
It might help to look at it like this:
if ((foo = bar)) {
} else {
foo = baz;
}
The if statement evaluates to the value of bar. If bar is false, null etc the evaluation would be false.
Edit: Note:
It is perfectly valid to evaluate an assignment. If we say:
if ((a = b)) { ...
note that it is not:
if (a === b) { ...
the evaluation is done on the result of the assignment. Here it would evaluate to true if (b).
One should however always wrap them in parenthesis. This makes it clear that we are evaluating the assignment and not comparing the variables.
If one do not like it that is fair enough, (I'm rather used to it from C), but in this case it is merely for the sake of the answer to the question.
In the same way we have:
if ((foo = foo)) {
} else {
foo = baz;
}
var x = false;
console.log((x = x)); // False
As such we can say:
(x = x) || (x = y)
And to make it short:
x = (x || y);
or shorter:
x = x || y;
The double pipe is called the 'or' operator.
The double pipe is the Logical OR operator in JavaScript.
If the technique had a name I guess it would be "(ab)using the short-circuiting of the logical OR operator"

What do you call the double pipe in javascript, as used in this context?

People often write this in order to specify default values:
var thing = this || that;
which is, AFAIK, the same thing as this:
var thing = !!this ? this : that;
What do you call the technique used to specify defaults in the first code block?
NOTE: I am not asking what a logical OR is called. I am asking what the alternative to ternary notation (as written in the first code block) is called.
I'd call:
var a = A || B;
conditional assignment, since it is effectively:
if (!!A) {
a = A;
} else {
a = B;
}
and it is a replacement for the conditional operator : ?
var a = A? A : B;
It might also be called "logical assignment" since it involves a logical OR expression, but it doesn't seem to fit with what it's doing.
As mentioned elsewhere it is a logical OR.
The evaluation in question is a short-circuit evaluation.
It might help to look at it like this:
if ((foo = bar)) {
} else {
foo = baz;
}
The if statement evaluates to the value of bar. If bar is false, null etc the evaluation would be false.
Edit: Note:
It is perfectly valid to evaluate an assignment. If we say:
if ((a = b)) { ...
note that it is not:
if (a === b) { ...
the evaluation is done on the result of the assignment. Here it would evaluate to true if (b).
One should however always wrap them in parenthesis. This makes it clear that we are evaluating the assignment and not comparing the variables.
If one do not like it that is fair enough, (I'm rather used to it from C), but in this case it is merely for the sake of the answer to the question.
In the same way we have:
if ((foo = foo)) {
} else {
foo = baz;
}
var x = false;
console.log((x = x)); // False
As such we can say:
(x = x) || (x = y)
And to make it short:
x = (x || y);
or shorter:
x = x || y;
The double pipe is called the 'or' operator.
The double pipe is the Logical OR operator in JavaScript.
If the technique had a name I guess it would be "(ab)using the short-circuiting of the logical OR operator"

Why does ( true && 1 ) return 1, but ( 1 && true ) returns true?

In C I know true and false evaluate to 1 and 0 respectively. show in this case just prints to the screen... Not sure what's going on here. I'm expecting to get true back. This 1 is messing up my karma.
show(1 && true);
true
show(true && 1);
1
Simply put - that's how && is defined. In Javascript, a && b returns a if a is falsy and b if a is truthy.
Conversely a || b returns a if a is truthy and b if a is falsy.
This makes sense intuitively - if a is false in a && b, then why bother reading the rest of the expression? You already know the whole thing is false. So just return false. But Javascript makes the decision to return a, which is falsy, instead of making up the value false to return out of nowhere.
This is based on short-circuit evaluation common to all C-style languages.
It allows for much expressiveness in Javascript. For instance this pattern:
var foo = function(opts) {
opts = opts || {}
// ...
}
Implements an optional parameter opts. If opts is not passed in at all, opts = opts || {} will set opts to {}, so the rest of the code does not have to know opts wasn't passed.
In long-hand it is equivalent to the following:
var x = a || b; // is equivalent to
var x;
if(a) {
x = a;
}
else {
x = b;
}
and
var y = a && b; // is equivalent to
var y;
if(!a) {
y = a;
}
else {
y = b;
}
Therefore Javascript can be much more terse than C or Java, because simple if statements can be replaced by || or && entirely. Sometimes this makes the code more terse and less readable and more like Perl, other times it allows for new Javascript patterns, like opts = opts || {}.
Another use is in patterns like
var displayName = user.fullname || user.email;
Which means "use the full name if available; if not, fall back to email." I personally find this expressive and readable, but it's arguably terse and obscure depending on which part of the Javascript community you hail from. Because of examples like this, and essentially the fact that truthy values are far more diverse then falsy values, using short-circuit || is much more common than short-circuit &&, as in your question.

Confused about Javascript hierarchy behavior (sample code given)

I am still relatively new to Javascript, and have been trying to wrap my head around how a particular library is managing such clean types and naming convention.
The library in question is Telerik's Kendo UI, and specifically I am curious how they are achieving something that reminds me of C# namespaces. For instance... there is a type called an ObservableArray, which can be accessed through kendo.ui.ObservableArray.
I dug into the source code and am really confused about what is going on. I have omitted a lot of the code for proprietary reasons, but the general closure shouldn't be an issue. I was wondering if someone could help me to grasp how they are achieving some of this...
(function ($, evil, undefined) {
var kendo = window.kendo = window.kendo || { cultures: {} },
extend = $.extend,
each = $.each; // more code omitted
function Class() { }
Class.extend = function (proto) {
// most of this code omitted
return subclass;
};
// more code omitted
})(jQuery, eval); // this line is really confusing me
Particularly, what has me lost beyond belief is that second line. Where they are declaring a variable (kendo) equal to a variable defined on window. I have searched high and low for hours and hours and cannot for the life of me figure out where this is first happening. I have been unable to reproduce the same behavior in my own code.
I have figured out that the extend function serves as a way to pair up an object with an existing object, and selectively attach it like an accessible member. But that window.kendo thing, it is driving me crazy.
It's not so complicated. Take this, for example:
var a, b, c;
a = b = c = 100;
Parentheses might help:
a = (b = (c = 100));
c = 100 is actually an expression. It assigns 100 to c and then evaluates to 100. So that progresses to:
a = (b = 100);
then it assigns 100 to b and further simplifies:
a = 100
And it finally also assigns 100 to a.
So when you have the following:
var kendo = window.kendo = window.kendo || { cultures: {} }
First it assigns the result of window.kendo || {cultures: {} } to window.kendo. Then it assigns that same result to the local variable kendo.
The final trick is what window.kendo || {cultures: {} } does, exactly. a || b evaluates to a if a is true, or b if a is false:
10 || 20; //evaluates to 10
undefined || 20; //evaluates to 20
undefined || null; //evaluates to null
So, if window.kendo is not defined yet, window.kendo || {cultures: {} } evaluates to {cultures: {} }. Otherwise, it evaluates to whatever window.kendo is, already.
This is a nifty way of specifying defaults, for example:
> function logit(s, label) {
label = label || "nolabel";
console.log(label + ": " + s);
}
> logit("Hey there")
nolabel: Hey there
> logit("Hey there", "Fooman")
Fooman: Hey there
window.kendo is a way to get a global variable named kendo.
kendo = window.kendo = window.kendo || { cultures: {} }
This will set the value of both the local kendo and the global kendo to either the value of the global if it exists, or if the global does not exist it will set it equal to that object literal.

The ternary operator and if A, B, else C. Are there any important differences?

There are a few ways to do this in javascript.
Foremost and most readable and flexible is probably:
if (a){
//b
}
else {
//c
}
Something else that only* works with assigning and is less readable is:
var foo = 'c';
if (a){
foo = 'b';
}
My main question, though, is about the last two methods I can think of:
var foo = a ? b : c;
var foo = a && b || c;
Are there any differences between these two expressions? Other than the readability which both lack.
*although you could assign foo to be a function, then execute it after the if statement.
Suppose:
var a = false, b = '', c = 'bar';
Then:
var foo = a ? b : c; // foo == ''
var foo = a && b || c; // foo == 'bar'
The two are not equivalent; you should never use the boolean operators in place of the conditional operator. Like other answerers, I also am of the opinion that the conditional operator does not lack readability for simple expressions.
The ternary operator is certainly readable to me. Even moreso than the first example, since concise, logical code is always easier to understand than many lines of control code that do the same thing.
I don't agree the first lacks readability as long as it is used correctly, IOW a, b and c are simple expressions themselves. This operator does get abused though in circumstances it ought not.
Similarly the second expression, using the result foo as anything other than a boolean would not be good. Using the boolean operators to return non-boolean values because thats the way they work is just confusing. However as a boolean expression its reasonable.
var foo = a ? b : c; // foo is b when a is true else c.
var foo = a && b || c; // foo is true if a and b are true or c is true.
They do not evaluate to the same result as the latter is a boolean expression, not using a ternary operator.

Categories