I am trying to play with objects alongside with Symbol.toPrimitive symbol in order to convert objects to primitives.
I used this code:
function UserEq(name) {
this.name = name;
this[Symbol.toPrimitive] = function (hint) {
alert("hint is: " + hint);
return 0;
};
}
function objectEqualityCheck() {
let user1 = new UserEq("John");
let user2 = new UserEq("Rambo");
if (user1 == user2) alert("Equal!");
}
And I expect two conversions resulting in alert Equal!, but that is not what's hapenning...
When used like user1 == 0 all works fine (conversion is to number though).
Why when two objects are compared, it does not work?
EDIT: it doesn't work with === as well.
The first rule in the docs for == defines this
The comparison x == y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
If Type(x) is the same as Type(y), then
Return the result of performing Strict Equality Comparison x === y.
TC39
user1 == user2
Here you're comparing same type so there's no type conversion happens at all
ToPrimitive is called only under these conditions
If Type(x) is either String, Number, or Symbol and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
Related
In my application I have to make two array datatypes(one is any[] and other is number[]) as equal using strictly equal.
my code is:
.component.ts
if (categoryIds === PhysicalPackageConst.nrtPatchCategory){
this.materialTypes = PhysicalPackageConst.nrtPatchMaterialType;
categoryIds = [];
}
In the above if condition it is showing as false if I make it as ===(if I use == it is showing the data(true) but not for ===)
package.constant.ts
export const PhysicalPackageConst = {
nrtGumCategory : [29],
nrtPatchCategory : [30]
So I want to make it as true for the above condition in strictly condition
Can anyone help me on this
Strict Equality Comparison (===) ("strict equality", "identity", "triple equals") : Strict equality compares two values for equality. Neither value is implicitly converted to some other value before being compared. If the values have different types, the values are considered unequal. If the values have the same type, are not numbers, and have the same value, they're considered equal. Otherwise to compare value.
var num = 0;
var str = '0';
console.log(num === str); // false
Abstract Equality Comparison (==) ("loose equality", "double equals") : The behavior for performing loose equality using == is as follows. Loose equality compares two values for equality after converting both values to a common type. After conversions (one or both sides may undergo conversions), the final equality comparison is performed exactly as === performs it.
var num = 0;
var str = '0';
console.log(num === str); // true
Equality comparisons and sameness
For your problem, it's logic to get those result, because you need to cast value of array :any[] to number and make strict compare.
let categoryIds: any[] = [];
let nrtPatchCategory: number = 30;
// browse categoryIds arrays (you can use any other method like for ...)
categoryIds.forEach(categoryId => {
if (Number(categoryId) === nrtPatchCategory) {
...
}
});
Note: For more detail of forEach() Array.prototype.forEach()
Exemple:
console.log(2 === Number('3')); // false
console.log(3 === Number('3')); // true
I've been playing around with arrays in JavaScript and cannot figure out why this happens:
console.log(0 == 0)
//true
console.log([] == 0)
//true
console.log(0 == [])
//true
console.log([] == [])
//false
console.log([] == ![])
// true
The empty array is equal enough to zero both left and right, but why isn't it equal to itself?
I realise that comparing two objects would not result true, but why are they coerced to 0 (or falsy, which shouldn't be the case) if you compare them to 0, while threated as an object if you compare them to the other array?
console.log(0 == [])
//true
You are trying to compare object with an integer, so your object is implicitly typecasted to equivalent integer value that is 0
console.log([] == [])
//false
as two objects are never equal
console.log([] == [])
That will compare whether array1 and array2 are the same array object in memory, which is not what you want.
In order to do what you want, you'll need to check whether the two arrays have the same length, and that each member in each index is identical.
console.log([].length == [].length)
// true
Since the complete answer is never given and I actually understand it now, I'll provide the answer myself.
I found this in the Ecma-262 pdf:
It basically reads that [] == 0 is the same as Number([]) == 0 which is the same as 0 == 0 which is true. This does not apply to strict ===.
There is no rule to compare objects other then rule number one, which is x is the same as y. This means the same in everything, also memory address. Since they are not sharing the same memory address, rule 10 applies (return false).
The comparison x == y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
If Type(x) is the same as Type(y), then
a. Return the result of performing Strict Equality Comparison x === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
Return false
This question is handled with the knowledge of object reference and type conversion more properly.First,in javascript, object value is stored by reference.So we can tell it is different from [] and [],because the two array correspond with two different addr in memory.Second, '==' is a not rigorous operation for both left and right, [] and 0 are both transformed to false.
I'm new in JavaScript, and I just discovered strange behavior that I can't understand:
var magicVar = Math.sin;
magicVar == true; // it returns false
magicVar === true; // it returns false
if (magicVar) console.log("???"); // it prints "???"
What is happening?
Thank you.
var magicVar = Math.sin;
From here on magicVar is a reference to the Math.sin function, which is actually an Object (see Function on MDN)
The Function constructor creates a new Function object. In JavaScript
every function is actually a Function object.
magicVar == true; // it returns false
This is false: from the Equality comparison and sameness on MDN if you compare an operand of type Object with an operand of type Boolean using the == operator you always get false (look at the Loose equality using == table).
[EDIT] As Bergi pointed out in the comments you could actually in some cases have objects that loosely compared to a boolean value return true.
What is actually happening behind the scenes is that the comparison algorithm described in ES6 ยง7.2.12 is applied.
7.2.12 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
ReturnIfAbrupt(x).
ReturnIfAbrupt(y).
If Type(x) is the same as Type(y), then Return the result of performing strict Equality Comparison x === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String, Number, or Symbol and Type(y) is Object, then return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then return the result of the comparison ToPrimitive(x) == y.
Return false.
In your case what happens is:
magicVar == true
magicVar == Number(true) // Step 9. x == ToNumber(y).
magicVar == 1
toPrimitive(magicVar) == 1 // Step 11. ToPrimitive(x) == y.
magicVar.toString() == 1
"function sin() { [native code] }" == 1
Number("function sin() { [native code] }") == 1 // Step 7. ToNumber(x) == y.
NaN === 1 // Step 3. x === y.
false
But comparing for example to an object like:
{
valueOf: function(){
return 1;
}
}
you would get:
true == {valueOf(){return 1;}} // it returns true
magicVar === true; // it returns false
This is trivially false, the types of the operands are different and the === operator checks for the operands to have same types and values.
if (magicVar) console.log("???"); // it prints "???"
As all the others answers have said magicVar here is in a Boolean context and gets coerced to true
magicVar is true as a value. It is true in the sense that it's not empty, it's not null or undefined. So, any non-null value would be a true value. But is this value equal to true ? No. It is true as a boolean not true as a value.
To summarize:
magicVar == true || magicVar === true; // returns false
Boolean(magicVar); // returns true
The concept to grasp here is the difference between truthy and falsy values compared to true and false booleans. See here for truthy and here for falsy
Long story short, an if condition passes if the expression is truthy, and magicVar is a function (truthy).
magicVar is not equal to true.
It is equal to the Math.sin function.
So, in the if statement, it is evaluated to a truthy value (it is defined and does not evaluate to a falsy value).
http://www.sitepoint.com/javascript-truthy-falsy/
Comparison function Math.sin with boolean constant return false, because this variables have different types.
But when you put not-bool variable to if condition: for example if (Math.sin)... or if (window)... this return true if variable not equal null.
In these example I am ruining a function with conditions;
function validPrice(price)
{
if(price=="" || price==0 || price==null || price==undefined )
{
//do something
}
else
{
// do something different
}
}
var priceNew = $("li#listedProd").attr("price");
validPrice(priceNew);
My question is what are the different in these condition price=="" || price==0 || price==null || price==undefined
Whoever first wrote that code was either
a) Being very defensive against future use.
b) Didn't understand how attr works.
The method attr (or the underlying call of getAttribute will return either
A string value, of the attribute is found
null, if it is not.
Importantly, should there have been a 0 value, it would be a string 0, and thus not caught in the test below -- caught against the price == 0 test because the system would have automatically converted it to a number as part of the == compare.
if(price=="" || price==0 || price==null || price==undefined )
And, due to the way that conversions work internally, those tests don't work as intended. == and === are different. It should be:
if(price === "" || price === 0 || price === null || price === undefined )
All of which can easily be reduced to simply "price" due how how coercion to boolean work:
if (!price)
Or, if you want to catch "0" values
if (!price || +price === 0)
(the +price forces price to be a number, so we catch 0 0.00 and other variations.)
Let's look at your conditional statement term-by-term:
price == ""
This is true if price is the empty string, and false otherwise.
price == 0
This is true if price is the integer 0, the string "0", or the empty string, and false otherwise. You should change this comparison to price === 0 if you want to catch when price is the integer 0.
price == null
This is true if price is passed to your function and is of the type null, and false otherwise.
price == undefined
Note: You should probably make this comparison via price === undefined to see that price is both undefined and has the type undefined.
This is true if price is not passed to your function, or if price is otherwise undefined, and false otherwise.
I would recommend just making the entire conditional statement !price:
function validPrice(price) {
if (!price) {
//do something
}
else {
// do something different
}
};
var priceNew = $("li#listedProd").attr("price");
validPrice(priceNew);
EDIT added definitions
JavaScript has 2 operators that test for equality (and conversely 2 operators that test for inequality.)
A strict equality comparison (e.g., ===) is only true if the operands are of the same type AND if the object is actually the same object, or the primitives have the same value (e.g., 0 === 0, and 'a' === 'a' are both true). *Note there is a slight exception to this rule for NaN (see below)
An abstract equality comparison (e.g. ==) converts the operands to the same Type (if they aren't already) before making a strict equality comparison. If however one of the operands is null or undefined, the comparison is true if and only if the other operand is either null or undefined.
So in short the == equality operator is considered by many to be unsafe. To see the difference checkout http://dorey.github.io/JavaScript-Equality-Table/
For instance '' ==: 0, '', [], false, [[]]
And 0 ==: false, 0, '0', '', [], [[]], [0]
While null ==: null, undefined
And finally undefined ==: null, undefined
It is better to use strict equal === or just test for a falsey value ('', 0, undefined, null, false)
if (!price) { //do something }
Below I have provided more details about strict vs abstract equality comparison
details came from ECMA-262, Edition 5 11.9.1
Summary of strict equality algorithm
1. If typeof(x) is different from typeof(y), return false.
2. If typeof(x) is undefined, return true.
3. If x is null, return true.
4. If typeof(x) is number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is -0, return true.
e. If x is -0 and y is +0, return true.
f. Return false.
5. If typeof(x) is string, then
a. If x and y are exactly the same sequence of characters (same length and same characters in
corresponding positions), return true.
b. Else, return false.
6. If typeof(x) is boolean, then
a. If x and y are both true or both false, return true.
b. Else, return false.
7. If x and y are the same Object value, return true.
8. Return false.
And ... details came from ECMA-262, Edition 5 11.9.1
Summary of Abstract Equality Algorithm
1. If typeof(x) is the same as typeof(y), then
return the result of performing strict equality comparison algorithm x === y.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If typeof(x) is number and typeof(y) is string,
return the result of the comparison x == Number(y).
5. If typeof(x) is string and typeof(y) is number,
return the result of the comparison Number(x) == y.
6. If typeof(x) is boolean, return the result of the comparison Number(x) == y.
7. If typeof(y) is boolean, return the result of the comparison x == Number(y).
8. If typeof(x) is either string or number and typeof(y) is object,
return the result of the comparison x == [[ToPrimitive]](y).
9. If typeof(x) is object and typeof(y) is either string or number,
return the result of the comparison [[ToPrimitive]](x) == y.
10. Return false.
[[ToPrimitive]] is an internal function call
Bullets 8 and 9 basically mean that objects are converted like object.valueOf().toString() so:
{} == '[Object object]'
{ hi: 'hi'} == '[Object object]'
{ valueOf: function(){ return 0; }} == 0
{ toString: function(){ return 'hi'; }} == 'hi'
{ valueOf: function(){ return 0; }, toString: function(){ return 'hi'; }} == 0
Full ecma-262/5.1/#sec-11.9 spec
var x = function() {};
var y = function() {};
alert(x === y); // is false;
Why is x not equal to y if they are both initialised to the same value?
When you compare objects in JavaScript, you are checking to see if they are the same object, not if they are identical objects.
From MDN:
If both operands are objects, then JavaScript compares internal
references which are equal when operands refer to the same object in
memory.
Clearly, your objects are distinct from each other, and refer to different memory locations. The equals comparison operator checks if both operands refer to the same object, not if they are are replicas.
Consider the fact that (new Number(1)) != (new Number(1)), whereas 1 == 1
Because they aren't the same function object. The comparator does not look at the function body.
The ECMA standard gives some precise rules on how strict equality works in JavaScript. Basically, as #Quentin said, if you are comparing two objects (other than Number, String, Boolean, null or undefined), it only returns true if they are the same object. That is not the case here.
Consider this code:
var x = function() {};
var y = function() {};
x.something = "this is x";
y.something = "this is not x";
alert(x.something === y.something);
This will give false.
From Spec-11.9.6:
The Strict Equality Comparison Algorithm
The comparison x === y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
1.If Type(x) is different from Type(y), return false.
2.If Type(x) is Undefined, return true.
3.If Type(x) is Null, return true.
...
7.Return true if x and y refer to the same object. Otherwise, return false.