As I try to understand why this ![] exression in Javascript is false, I've got stuck. I understand that [] is considered truthy, and that !true is false but I'd like to dive deeper.
According to the Spec the unary NOT operator works like this:
Let oldValue be ToBoolean(GetValue(expr)).
If oldValue is true, return false.
Then I tried to understand GetValue([]) and it's all blurry right now. Spec sec-8.7.1
Does GetValue([]) simply returns [].valueOf()?
GetValue called with a plain value (not a Reference) returns just that plain value - in your case the array. Otherwise it would evaluate the reference to an identifier (in a variable scope) or property (in an object), but that's not the case in your example.
On that same page, see 8.7.1 for a description of how GetValue is implemented:
https://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
(it has nothing to do with valueOf)
Evaluate GetValue([]), then evaluate ToBoolean on the result, per the spec.
Related
I have recently read some code that uses !! to convert a variable to boolean for evaluation in an if statement. This seems somewhat redundant to me as the variable would be evaluated for its boolean value anyway. Are there any performance benefits to doing this or is it for better browser support?
Sample Code:
var x = 0;
var atTop = x===window.scrollY;
if(!!atTop){
alert("At the top of the page.");
}
Edit:
I have also seen this for operands that are not of boolean types, but I had always assumed that using if would evaluate the boolean value of the variable anyway as all values in Javascript are either "truthy" or "falsey".
Sample Code:
var x = 1;//or any other value including null, undefined, some string, etc
if(!!x){//x is "truthy"
//wouldn't using if(x) be the same???
console.log("something...");
}
Short answer: No, there is no reason.
In your code, it's already a boolean type, there is no need to convert, and convert it back again: you will always get the same result. Actually, if you have a boolean value (true or false), when you use !! with any of them, it will be converted back to its original value:
console.log(!!true); // Will always be "true"
console.log(typeof !!true); // It's still a "boolean" type
console.log(!!false); // Will always be "false"
console.log(typeof !!false); // It stills a "boolean" type
Answer for edited question: Yes, it's the same. That's what if(...) actually does - it's trying to convert any type to boolean.
Here is a small test, you can play around with that and add whatever you want inside the initialArr array in order to test whether it behaves the same with if and !!:
const initialArr = [
undefined,
null,
true,
false,
0,
3,
-1,
+Infinity,
-Infinity,
Infinity,
'any',
'',
function() { return 1 },
{},
{ prop: 1 },
[],
[0],
[0, 1]
];
function testIsTheSame(arr) {
let equolityCounter = 0;
arr.forEach(item => {
let ifStatement = false;
let doubleNotStatement = !!item;
if (item) {
ifStatement = true;
}
if (
ifStatement === doubleNotStatement &&
typeof ifStatement === typeof doubleNotStatement
) {
equolityCounter++;
}
});
console.log(`Is the same: ${equolityCounter === arr.length}`);
}
testIsTheSame(initialArr);
I would say it was mostly done for code-readability. I doubt there is any significant performance nor compatibility implications (someone feel free to test this please)
But in the code-readability aspect, it would imply to me that this variable previously was not a boolean, but we want to evaluate it as one, if you add new logic concerning this variable, keep that in mind.
Although in your case its already boolean, so its 100% redundant, but I'd guess just a habit of someone for the above reasoning applied excessively, and/or seeing it elsewhere and copying that pattern without fully understanding it (short story time: in C# you can name a protected term a variable name by adding #, so var #class = "hello";, a junior dev just assumed all variable names needed # in front of them, and coded that way. I wonder if someone assumed that an if without a comparison operator needs to have !! in front of it as a comparison operator)
There isn't any run-time benefit (or an objective one) whatsoever to doing this in an if statement. The evaluation performed by the if statement will yield precisely the same result as the evaluation produced by double exclamation mark. There is no difference.
Double exclamation marks is a useful expression to ensure boolean value based on truthyness. Consider, for instance:
var text = undefined;
console.log(text); // undefined
console.log(!!text); // false
// It would make sense here, because a boolean value is expected.
var isTextDefined = !!text;
// It would also affect serialization
JSON.stringify(text); // undefined (non-string)
JSON.stringify(!!text); // "false"
I suppose that this is a habit that was picked up because of the above use cases, thus always converting to boolean when wishing to address a variable's truthyness. It's easier for us (humans and programmers) to follow a rule when it's always applied. You'll either use the blinkers in your car all the time, even when there's nobody around, or it's likely that you'll occasionally (or maybe often) forget to signal when you should have.
It all depends on the value of atTop variable. Follow the discussion here.
In summary, if the value of atTop is anything different to a boolean, the first negation will convert it to a boolean value (negated). Second negation will return the boolean value to the equivalent boolean of the original atTop value.
For example, if atTop is undefined, first ! will turn it to boolean true, then the second ! turns it to boolean false (which would be the equivalent boolean of undefined)
However, in your code the atTop value is the result of an strict equality ===, which means you always get a boolean as a result in atTop. Thus, you don't need to convert a non-boolean value to boolean, and so, the !! is not needed.
I'm trying to understand the below block of syntax (taken from angular docs to represent the use of angular noop as an 'empty' function)
function foo(callback) {
var result = calculateResult();
(callback || angular.noop)(result);
}
I don't understand the '||' syntax. I tried looking it up but had trouble searching and wasn't really sure what to search.
Thinking of it as 'OR' syntax, it would mean to me if a function was assigned to the callback or if the function was assigned to angular noop would equal true and then a function is being called on true. But obviously that's wrong
Apologies in advance for the newbishness of the question.
- EDIT -
To clarify further, I'm aware of what it does guessing from the example. However, I'm trying to figure out what javascripts rule say that would cause the return statement for (callback1 || callback2) to return a function object instead of a boolean (as implied by the fact that in the example you can call the return of the sub-expression).
This bit
(callback || angular.noop)(result);
is short for:
if (callback) {
callback(result);
} else {
angular.noop(result);
}
It takes advantage of the fact that || is lazily executed. The search term you're looking for is lazy evaluation. To explain the "why" on how this works, we can take a look at the ECMAScript specification, specifically 11.11 Binary Logical Operators,
The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions. Note that this doesn't mean that you can't depend on an expression such as:
if (a || b) // <-- logical expression will evaluate to the value of a or b, NOT true or false
because JavaScript evaluates boolean values as truthy or falsy, formally defined as the operation ToBoolean() in the ECMAScript specification.
From 9.2 ToBoolean
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Argument
Type Result
Undefined false
Null false
Boolean The result equals the input argument (no conversion).
Number The result is false if the argument is +0, −0, or NaN;
otherwise the result is true.
String The result is false if the argument is the empty String
(its length is zero); otherwise the result is true.
Object True
Basically the statement
(callback || angular.noop)(result);
Can be read as:
Call the function callback or angular.noop with the argument of result
If callback is not defined the OR (||) will be evaluated to call the angular.noop function passing the variable result to the function.
The angular.noop() function is a function that does nothing. More read here https://docs.angularjs.org/api/ng/function/angular.noop
What does if(a) exactly check in javascript? Can it check undefined? Can it check null? Can it check an empty string?
When do we need to use typeof a == 'undefined' or it could be covered by if(a)?
if evaluates a in a boolean context and uses the result to determine which code branch to execute. undefined, null and the empty string all evaluate to false in a boolean context.
typeof a === "undefined" is useful to check if the name a is defined (e.g. if a variable with that name exists in the current scope). Without this construct, accessing a directly would throw an exception if it is not defined.
Taken from the ECMAscript language specification, the if-Statement works as the following:
12.5 The if Statement
The production IfStatement : if ( Expression ) Statement is evaluated as follows:
Let exprRef be the result of evaluating Expression.
If ToBoolean(GetValue(exprRef)) is false, return (normal, empty, empty).
Return the result of evaluating Statement.
Means, in such cases, it would try a toBoolean conversion which acts like this:
Table 11 - ToBoolean Conversions
Undefined: false
Null: false
Boolean: The result equals the input argument (no conversion).
Number: The result is false if the argument is +0, -0, or NaN; otherwise the result is true.
String: The result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Object: true
It checks for a value not being false-ish, i. e. false, 0, undefined and null or an empty string. typeof a == 'undefined' is useful when you are curious if a value is undefined or not, since if (a) can't make the distinction between the false-ish values.
The conditional statement will only check for 'true' or 'false'.
in case of undefined the condition is not satisfied and control does not go into the loop.
typeof returns the type of operand. for details you may want to see this link
following values are considered as false in javascript conditions: false, null, undefined,'', 0, NaN
the answer by h2co3 is actually almost correct, you can not check for undefined variables in an if without typeof as this will cause a script error.
if you do this:
<script>
if (a) alert('hello');
</script>
you will get a script error and the if will not be evaluated (the result is the same in the sense that alert is not shown, but that's because the thread execution ended due to the script error.)
if you want to make sure a is defined you need to use the typeof test.
var boolTrue = true;
var randomObject;
if (boolTrue)
// this will fire
if (randomObject)
// this will fire, because the object is defined
if (!objectNotDefined)
// this will fire, because there is no defined object named 'objectNotDefined'
Coming from a C++ and C# background, I am very familiar with the basic if(expression) syntax. However, I think it is not very readable to have both expressions (true/false) and have object existence also being a expression. Because now if I see a function like below, i don't know if the data coming in is an object (existence/undefined check) or a boolean.
function(data) {
if (data)
// is this checking if the object is true/false or if the object is in existence?
}
Is this just the way it is? I mean, is there anyway to easily read this? Also, where is this documented anywhere in the JS spec (curious)?
In Javascript everything is "true" (or "truthy" to be more precise using Javascript parlance) except false, 0, undefined, null, NaN and empty string.
To avoid confusion use:
if (data === true) // Is it really true?
and
if (typeof data === 'undefined') // Is the variable undefined?
You can check for (non-)existence separately:
if ( typeof variable == 'undefined' ) {
// other code
}
However, the syntax you show is commonly used as a much shorter form and is sufficient in most usecases.
The following values are equivalent to false in conditional statements:
false
null
undefined
The empty string ”
The number 0
The number NaN
It checks whether it is truthy.
In JavaScript, everything is truthy except false, 0, "", undefined, null and NaN.
So, true will pass, as well as any object (also empty objects/arrays/etc).
Note that your third comment is true if you mean "declared but not defined" - a variable that has never been declared throws a ReferenceError on access. A declared, non-defined variable (var something;) is undefined (so, not truthy) so it will indeed pass the condition if you negate it.
We can do:
NaN = 'foo'
as well as
undefined = 'foo'
Why are they not reserved keywords?
I think it should be implemented in order to be sure that when we are looking for a number, it is a number :)
If we should use IsNaN() or typeof, why are NaN or undefined needed?
I cannot tell you why, but undefined and NaN are actually properties of the global object:
15.1.1 Value Properties of the Global Object
15.1.1.1 NaN
The value of NaN is NaN (see 8.5). This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
(...)
15.1.1.3 undefined
The value of undefined is undefined (see 8.1). This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
There is a difference between the value undefined (NaN) and the corresponding property.
You might notice the [[Writable]]: false. I'm not sure whether this new in ES5 (and might not be adapted by all browsers), but in newer browsers (tested in Firefox 6), assigning a new value to undefined has no effect:
[12:28:15.090] < undefined = "foo"
[12:28:15.093] > "foo"
[12:28:19.882] < undefined
[12:28:19.883] > undefined
So although it seems you can assign a new value, you actually cannot.
Why they are not reserved keywords?
Not sure if there was a specific reason to not make them reserved keywords, but it was decided against it. The language still works. You cannot override these values, so it's fine.
The only way to test whether a number is NaN, is to use isNaN() anyway.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/NaN
NaN is a property of the global object.
The initial value of NaN is Not-A-Number — the same as the value of
Number.NaN. In modern browsers, NaN is a non-configurable,
non-writable property. Even when this is not the case, avoid
overriding it.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/undefined
undefined is a property of the global object, i.e. it is a variable in global scope.
The initial value of undefined is the primitive value undefined.
I'm speculating now, but the reason why I think NaN and undefined are not keywords is because you generally don't assign these values to variables.
var x = undefined; // doesn't make sense, use null!
var y = NaN; // You can't do much with this variable!
undefined basically means uninitialized, and if you want to make it clear that the value is unknown you use null. So undefined usually means not-initialized or the result of JavaScript code gone wrong.
NaN Is rarely assigned manually, simply because you can't do much with this value. It is usually the result of a calculation gone wrong. The makers of JavaScript probably didn't want to give this value the visibility of primitive values.
Also, NaN is also present in other languages and it isn't used as a keyword there either. For example: In C# NaN is represented by Double.NaN, since you don't make a distinction between floating point and integer values in JavaScript, I'm guessing that's why they put NaN with the Global Identifiers!
I hope this clears things up!
Both NaN and undefined are values in JavaScript.
NaN is of number type. (it denotes "not a valid number").
undefined is of undefined type. (when there is nothing assigned to a variable, JavaScript assigned undefined particular in var declaration).
And also both are read-only values(property) of global window object.
So that's why JavaScript cannot make values as a reserved word.
NaN is not a keyword, but it is rather a built-in property of the global object, and as such may be replaced (like undefined, but unlike the keyword this or the literals true, false, and null).
You can test if a value is NaN with the isNaN() function. Moreover NaN is defined to be unequal to everything, including itself.
Or in a nutshell you can say that:
NaN is the value returned when you try to treat something that is not a number as a number. For instance, the results of 7 times "abc" is not a number. The old form of it is Number.NaN. You can test for not-a-number values with the isNaN() function.
One reason is that it is possible to use those words as object keys:
messages = {
NaN: 'that was not a number',
undefined: 'that was not initialized',
default: 'that was something' // not in the original question but is valid syntax
};
console.log (messages.NaN);
While it would be possible to use { 'NaN': 'that was not a number' } and console.log(messages['NaN']), leaving as many words as possible unreserved could make your code easier to read.