Why does comparing an explicitly called String constructor to an implicit string evaluate true, but adding the new keyword makes it evaluate false on deep equals, but true again on shallow equals?
> "hello"===String("hello")
true
> "hello"==new String("hello")
true
> "hello"===new String("hello")
false
Edit: after further testing, this appears to happen with all types that have implicit constructors.
Edit 2: to clarify, this is not a question of == vs. ===, but one of implicit vs. explicit constructors.
When you use the new keyword you are creating an object. If you were to check the typeof new String('hello') you will see that it is of type object. Checking the type of 'hello' on its own will yield string.
As you may know, using a strict equals operator (===) will check for both value and type, so it will return false due to the types not matching.
The reason the expression without the new keyword returns true is because calling upon the String global object is not the same as calling the constructor using new:
String literals (denoted by double or single quotes) and strings returned from String calls in a non-constructor context (i.e., without using the new keyword) are primitive strings.
As such, the type of the return value will be string and not object, so the strict check will return true.
The difference between == and === is that === requires the type to be the same, while == does not.
So this is telling you that both "hello" and String("hello") are of the same type (which is string); but new String("hello"), while it has the same value, is a different type (which is object)
Related
I am wondering why the Boolean coercion fails in this case:
!!(new Boolean(false)) === true
Although:
(new Boolean(false).valueOf()) === false
Mozilla says:
Booleans are returned as-is.
I am wondering what "as-is" means in the context of a coercion. I thought "coercion" means "convert anything to a primitive boolean". How is it possible that something which is meant to be false gets coerced to true?
BTW: Consequently this fails too:
Boolean(new Boolean(false)) === true
It seems to me, that the Boolean class itself is an error. Maybe I have to use the following code:
if (arg instanceof Boolean)
throw new Error("Stop doing nonsense")
Or maybe this:
function coerce_boolean_correctly (arg) {
if (arg instanceof Boolean)
return coerce_boolean_correctly(arg.valueOf())
return !!arg
}
There is a huge difference between a Boolean object and a Boolean primitive. The MDN page you referenced, actually warns about this at the very outset:
Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object.
Any object, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement.
And this (what I marked in bold) is exactly what happens in your code: it creates a new Boolean(false) and that will coerce to true -- in other words it is a truthy value. In your code you have explicitly converted it to a boolean primitive, by applying ! to it twice. In either case (implicit coercion or explicit conversion) new Boolean(false) is truthy. Fact is that all objects are considered truthy (when coerced to boolean, they evaluate to true).
The article continues with:
Do not use the Boolean() constructor with new to convert a non-boolean value to a boolean value — use Boolean as a function or a double NOT instead.
This suggests that your code should be modified to drop the use of new, and call Boolean as a plain function, not as constructor:
!!(Boolean(false)) === false
When Boolean is called as plain function, it returns a primitive boolean (false or true). But anything that is called as constructor, even Boolean, will return an object. And objects are truthy.
When in the context of coercion MDN states "Booleans are returned as-is." they refer to boolean primitives. (Boolean) objects are covered by the last bullet point in the same list: "All objects become true". The latter in includes Boolean objects.
A Boolean object has a valueOf method which returns a boolean primitive, and so it returns what you would intuitively expect.
The MDN article rightly says:
Warning: You should rarely find yourself using Boolean as a constructor.
Don't use new Boolean, but Boolean.
If for some reason you have a Boolean object, really ask yourself why you have that object in the first place. Tackle the code that created that object and use a primitive boolean from the outset.
Objects are truthy
Some are surprised in a similar way that the following holds:
if (!!new String("")) console.log("An empty string is truthy!?");
if (!!new Number(0)) console.log("The number 0 is truthy!?");
if (!!new Number(NaN)) console.log("NaN is truthy!?");
if (!!new Object(null)) console.log("null is truthy!?");
if (!!new Object(undefined)) console.log("Undefined is truthy!?");
It is the same principle: objects are truthy. Always.* No matter what their constructor is named. No matter what value was passed to that constructor.
* document.all is an abhorrent, but accepted, violation of this rule.
See also
What's the point of the Boolean object?
What is the purpose of new Boolean() in Javascript?
I have examined the wrapped symbol objects using the following code.
const symObj = Object(sym);
const symObjNew = new Object(sym);
// I can see no difference between symObj and symObjNew
console.log(`typeof symObj === 'object' is ${typeof symObj === 'object'}`); // true
console.log(`typeof symObjNew === 'object' is ${typeof symObjNew === 'object'}`); // true
I have also examined the symObj and symObjNew in devtools using node --inspect-brk. I don't see any difference between them. The same is true of BigInt.
TL;DR
There is no difference between new Object(realthing) and Object(realthing). They do the same thing.
Much longer answer
When it comes to JS, reading the spec is always a good idea, although it can be incredibly hard to figure out what things mean. So, let's dive into this: in this case, we want the rules for how Object() works:
19.1.1The Object Constructor
The Object constructor:
is the intrinsic object %Object%.
is the initial value of the Object property of the global object.
creates a new ordinary object when called as a constructor.
performs a type conversion when called as a function rather than as a constructor.
is designed to be subclassable. It may be used as the value of an extends clause of a class definition.
So we have two cases to look at: Object(sym), and new Object(sym).
What happens for Object(sym)?
19.1.1.1 Object([ value ])
When the Object function is called with optional argument value, the following steps are taken:
If NewTarget is neither undefined nor the active function, then
Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
Return ! ToObject(value).
(Note that ? and ! here are not "code", they are spec syntax. ! means "this operation will always return a normal value whereas ? may return an abnormal value)
In this case, we didn't use new, so step 1 doesn't apply. The value is not nullish, so step 2 doesn't apply, and we end up executing step 3: we perform a type conversion so we end up with a new object for which typeof will now say "object", no matter what it was before, but with the original data preserved as value.
What happens for new Object(sym)?
Looking at 19.1.1.1 again, we're using new this time, so we might expect step 1 to kick in: after all, there is a NewTarget (by definition: we used new so there is a NewTarget), but it turns out the NewTarget is the Object function itself, making NewTarget the active function, and so step 1a does not kick in.
We also have a value, and it's not nullish, so step 2 doesn't kick in, and we again run step 3: type conversion.
So Object(sym) and new Object(sym) do exactly the same thing, just for subtly different reasons.
So how does ToObject work?
Looking at the spec again:
7.1.13ToObject ( argument )
The abstract operation ToObject converts argument to a value of type Object according to Table 12:
Undefined Throw a TypeError exception.
Null Throw a TypeError exception.
Boolean Return a new Boolean object whose [[BooleanData]] internal slot is set to argument. See 19.3 for a description of Boolean objects.
Number Return a new Number object whose [[NumberData]] internal slot is set to argument. See 20.1 for a description of Number objects.
String Return a new String object whose [[StringData]] internal slot is set to argument. See 21.1 for a description of String objects.
Symbol Return a new Symbol object whose [[SymbolData]] internal slot is set to argument. See 19.4 for a description of Symbol objects.
Object Return argument.
So the first observation should be that "if it's an object, ToObject does nothing". That's of course not the case for your Object(sym), so what happens for it?
A new object gets built, with its type set to object (irrespective of what the input value type is), and this new object's prototype will be set to match whatever the input value's prototype was. Then the new object's internal value literally gets copied over from the input value that's getting converted.
But we're not quite done
typeof is useless for testing "what a thing is".
Remember that almost everything in JS is an object, and typeof will only tells you the basic type of something. As such, there are only six answers it can give you:
object
function
string
symbol
number
undefined
That's it. The typeof operator tells you nothing about the what the most specific type is, instead it tells you what the most generic type is.
For the specific type, either use thing.constructor.name to find out which constructor function actually got used to build the thing you're examining, or use thing.__proto__ to get a reference to that type. Or, if you have the type already and merely need to test to see if "thing is a ...", use the instanceof operator:
> typeof 3
"number"
> typeof Object(3)
"object"
> Object(3).constructor.name
"Number"
> Object(3).__proto__
Number { 0 }
> Object(3) instanceof Number
true
As specified in MDN:
When called in a non-constructor context, Object behaves identically to new Object().
I'd venture to guess this is another one of JavaScript's infamous backwards compatibility 'features', back during such a time that the new keyword didn't exist.
You can also check the ECMAScript spec for details:
When the Object function is called with optional argument value, the
following steps are taken:
If NewTarget is neither undefined nor the active function, then
Return ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
If value is undefined or null, return OrdinaryObjectCreate(%Object.prototype%).
Return ! ToObject(value).
As thoroughly explained by Mike's answer, both cases in your sample snippet end up in Step 3, which performs type conversion on the argument. So there is no difference whatsoever.
This question already has answers here:
Why does instanceof return false for some literals?
(10 answers)
Closed 7 years ago.
The following indicates the expression "true instanceof Boolean" evaluates to false. Why would this expression evaluate to false?
$(document).ready(function() {
var $result = $('#result');
if(true instanceof Boolean) {
$result.append('I\'m a Boolean!');
} else {
$result.append('I\'m something other than a Boolean!');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
The value true is a boolean primitive — that's "boolean" with a lower-case "b". It is not an object.
Similarly, "hello" is not an instance of String, because a string primitive is not an object either.
You can test for primitive types with the typeof operator.
The distinction between primitive values and object values can be a little confusing in JavaScript because the language implicitly wraps primitives in appropriate object wrappers when primitives are used like object references. That's why you can write
var length = "hello world".length;
The string is implicitly converted to a String instance for that . operation to work. You can even do that with a boolean:
var trueString = true.toString();
It happens with numbers too, though the syntax gets in the way sometimes:
var failure = 2.toString(); // an error
var success = (2).toString(); // works
The Boolean object is an object wrapper for a boolean value.
So the boolean value and the wrapper object are not the same thing.
Also, boolean objects are verboten. In other words it isn't good style to ever use a Boolean object.
+true // result: 1
true.valueOf() // result: true
+true === true.valueOf() // result: false
In Javascript Type Coersion, the function called for evaluation is valueOf(). But if the function is called explicity it returns a different value.
Type Coersion in Javascript happens if == is used, which is kinda loose comparison operator.
=== is strict comparison operator which doesn't coerce the types when comparing so it remains an integer and the other one bool
+true === true.valeOf() // false
+true == true.valueOf() // true
Docs:
The identity (===) operator behaves identically to the equality (==)
operator except no type conversion is done, and the types must be the
same to be considered equal.
Why true.valueOf() doesn't returns 1
The answer is true.valueOf returns true, which is the primitive value of a Boolean object. Also the quote is from MDN
The valueOf method of Boolean returns the primitive value of a Boolean
object or literal Boolean as a Boolean data type.
What does +true do:
+true is same as Number(true) and it is a well known fact that 0 is false and 1 is true in almost every language. In fact in C++ they are used as booleans.
the function called for evaluation is valueOf()
Not always. valueOf() is only meaningful for non-primitive types, since it is defined to return the primitive value of the given object. true by itself is a Boolean primitive and as such calling true.valueOf() would be completely redundant.
The unary + and - sign operators always return a number by definition. Since a Boolean quite conveniently converts to a number, it only makes sense that +true returns 1.
There is no reason +true and true.valueOf() should both correspond to the same value.
for strict comparison you should do like this:
Number(true.valueOf()) === +true
What is the use of:
var flag = new Boolean(false);
compared to:
var flag = false;
When would you actually use new Boolean?
The global function Boolean() can be used for type casting when called without new, eg
var foo = Boolean(bar); // equivalent to `var foo = !!bar`
When called with new, a wrapper object will be created additionally, which means that you can assign arbitrary properties to the object:
var foo = new Boolean(bar); // equivalent to `var foo = Object(Boolean(bar));`
foo.baz = 'quux';
alert(foo.baz);
This is not possible with primitive values as primitives can't hold properties:
var foo = true;
foo.baz = 'quux';
alert(foo.baz); // `foo.baz` is `undefined`
Assigning a property to a primitive doesn't produce an error because of auto-boxing, ie
foo.baz = 'quux';
will be interpreted as
// create and immediately discard a wrapper object:
(new Boolean(foo)).baz = 'quux';
To get the primitive value back, you'll have to invoke the valueOf() method. This is needed if you want to actually use the wrapped value, because objects always evaluate to true in boolean contexts - even if the wrapped value is false.
I've never come across a useful application of being able to assign properties to booleans, but boxing might be useful in cases where a reference to a primitive value is needed.
While others mentioned the theory, let me talk about the practical part:
Because Boolean objects (as objects in general) are always truthy, it is considered bad practice to use them. In many years of JS programming, I have never used them, and I can't remember seeing Booleans in other peoples' code either. Not even once.
Using primitive values will avoid confusion and will make your code a little bit shorter.
If you ever need a bool wrapped in an object, you might as well use an Object object like so:
foo = { value: false };
Also, calling the Boolean() constructor as a function (as in foo = Boolean(bar)) has the same effect as explicit typecasting using !!, and the latter is generally preferred over the former.
Before the above question first the Boolean function, Boolean ()
Boolean(10 > 4) // return true
Boolean(4 > 9) // return false
Next: everything with real value return true. E.g
100
-4
4.4
"hello"
"false" // note even the string value false return true.
everthing without real value return false E.g
NaN
var x = 10 / "H"; // Boolean(x); return false.
undefined
""
0
-0
false
null
Now the Boolean object is an object wrapper for a boolean value. The value passed as the first parameter is converted to a boolean value, if necessary. If value is omitted or is 0, -0, null, false, NaN, undefined, or the empty string (""), the object has an initial value of false. All other values, including any object or the string "false", create an object with an initial value of true.
This allows very powerful tricks.
Interesting question:
You use new Boolean to create a boolean object. There can be many scenarios but I have discussed below one scenario.
Suppose you want a comparison in your code where you want to match string value and its datatype and it has to bool (true/false) then you will use new boolean instead of assigning simple false value.
var flag = false;
var flag2 = new Boolean (false);
alert(typeof flag); //boolean object
alert(typeof flag2); //simple object
if (flag === flag2){
alert("Value and datatype match");
}
else{
alert("Value and datatype do not match");
}