Comparison Operators page
This week we covered comparisons in JavaScript! The showdown between == and === is on!
Overview
- Byte comparisons
- Memory address comparisons
==
state machine===
state machine- Live examples!
Video
Slides
Exercise
Implement the eqeq
function. Click Run in your browser
after the following example:
<p>Welcome to the <code>==</code> exercise! Open the JavaScript panel
to implement the <code>eqeq()</code> function. </p>
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.12.0.css">
<script src="//code.jquery.com/qunit/qunit-1.12.0.js"></script>
<script type="module">
// Start by filling this function out!
// eqeq(null, undefined) //-> true
var eqeq = function(value1, value2){
};
// The following functions might be useful to
// eqeq(). You’ll have to implement them yourself.
// Returns true if the value is `null` or `undefined`
var isNullOrUndefined = function(value) {
};
// Given a value, returns the primitive version of it,
// either a number or string.
var toPrimitive = function(value) {
};
// Given an object and a property on the object, this
// will return the property value as long as the property
// is not on `Object.prototype`. If you don’t know what
// this means, copy it from the answer key :-).
var getDefinedPropertyNotOnObjectPrototype = function(obj, prop) {
}
// Test code. There’s no need to edit the following:
QUnit.module("Double Equal", {});
QUnit.test("Types the same", function(){
QUnit.equal( eqeq(1,1), 1 == 1 , "1==1");
QUnit.equal( eqeq('1','1'), '1' == '1' , "'1'=='1'")
QUnit.equal( eqeq({},{}), {} == {} , "{}=={}")
QUnit.equal( eqeq(NaN,NaN), NaN == NaN , "NaN==NaN")
});
QUnit.test("Both null or undefined", function(){
QUnit.equal( eqeq(null,undefined), null == undefined , "null==undefined");
QUnit.equal( eqeq(undefined,null), undefined == null, "undefined==null");
});
QUnit.test("String == Number", function(){
QUnit.equal( eqeq(1,'1'), 1=='1' , "1=='1'");
QUnit.equal( eqeq(1,'2'), 1=='2', "1=='2'");
QUnit.equal( eqeq(1,'a'), 1=='a', "1=='a'");
QUnit.equal( eqeq('1',1), '1'==1 , "'1'==1");
QUnit.equal( eqeq('a',1), 'a'==1, "'a'==1");
});
QUnit.test("Boolean == Anything", function(){
QUnit.equal( eqeq(true,1), true==1 , "true==1");
QUnit.equal( eqeq(true,2), true==2 , "true==2");
QUnit.equal( eqeq(true,'true'), true=='true' , "true=='true'");
QUnit.equal( eqeq(true,'1'), true=='1' , "true=='1'");
QUnit.equal( eqeq(false,0), false==0 , "false==0");
QUnit.equal( eqeq(false,'false'), false=='false' , "false=='false'");
QUnit.equal( eqeq(false,'0'), false=='0' , "false=='0'");
QUnit.equal( eqeq(1,true), 1==true , "1==true");
QUnit.equal( eqeq(2,true), 2==true , "2==true");
QUnit.equal( eqeq('true',true), 'true'==true , "'true'==true");
QUnit.equal( eqeq('1',true), '1'==true , "'1'==true");
});
QUnit.test("Object == (String || Number)", function(){
QUnit.equal( eqeq(({toString: function(){return 1}}),1), ({toString: function(){return 1}})==1 , "({toString: function(){return 1}})==1");
QUnit.equal( eqeq(({toString: function(){return '1'}}),1), ({toString: function(){return '1'}})==1 , "({toString: function(){return '1'}})==1");
QUnit.equal( eqeq(({toString: function(){return true}}),1), ({toString: function(){return true}})==1 , "({toString: function(){return true}})==1");
QUnit.equal( eqeq(({valueOf: function(){return 1}}),1), ({valueOf: function(){return 1}})==1 , "({valueOf: function(){return 1}})==1");
QUnit.equal( eqeq(({valueOf: function(){return '1'}}),1), ({valueOf: function(){return '1'}})==1 , "({valueOf: function(){return '1'}})==1");
QUnit.equal( eqeq(({valueOf: function(){return true}}),1), ({valueOf: function(){return true}})==1 , "({valueOf: function(){return true}})==1");
QUnit.equal( eqeq(({toString: function(){return 1}}),true), ({toString: function(){return 1}})==true , "({toString: function(){return 1}})==true");
QUnit.equal( eqeq(({toString: function(){return '1'}}),true), ({toString: function(){return '1'}})==true , "({toString: function(){return '1'}})==true");
QUnit.equal( eqeq(({toString: function(){return true}}),true), ({toString: function(){return true}})==true , "({toString: function(){return true}})==true");
QUnit.equal( eqeq(({valueOf: function(){return 0}}),false), ({valueOf: function(){return 0}})==false , "({valueOf: function(){return 0}})==false");
QUnit.equal( eqeq(({valueOf: function(){return null}}),false), ({valueOf: function(){return null}})==false , "({valueOf: function(){return null}})==false");
QUnit.equal( eqeq(({valueOf: function(){return undefined}}),false), ({valueOf: function(){return undefined}})==false , "({valueOf: function(){return undefined}})==false");
// odd one
QUnit.equal( eqeq('a', ({valueOf: function(){return true}, toString: function(){ return 'a' }})), 'a' == ({valueOf: function(){return true}, toString: function(){ return 'a' }}) , "'a' == ({valueOf: function(){return true}, toString: function(){ return 'a' }})");
QUnit.equal( eqeq(1, [1]), 1 == [1] , "1 == [1]");
// Hard one
QUnit.equal( eqeq( "abc" , Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}}) ), "abc" == Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}}) , '"abc" == Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}})');
});
</script>
Solution
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.12.0.css">
<script src="//code.jquery.com/qunit/qunit-1.12.0.js"></script>
<script type="module">
var eqeq = function(value1, value2){
var type1 = typeof value1,
type2 = typeof value2;
if(type1 === type2) {
return value1 === value2
}
if(isNullOrUndefined(value1) && isNullOrUndefined(value2)) {
return true;
}
if(type1 === "string" && type2 === "number") {
return eqeq( toPrimitive(value1), value2 );
}
if(type2 === "string" && type1 === "number") {
return eqeq( value1, toPrimitive(value2) );
}
if(type1 === "boolean") {
return eqeq(toPrimitive(value1), value2);
}
if(type2 === "boolean") {
return eqeq(value1, toPrimitive(value2));
}
if(value1 && type1 === "object") {
return eqeq(toPrimitive(value1), value2);
}
if(value2 && type2 === "object") {
return eqeq(value1, toPrimitive(value2));
}
return false;
};
var isNullOrUndefined = function(value) {
return value === null || value === undefined;
};
var toPrimitive = function(value) {
if(typeof value === "string") {
return +value;
}
if(typeof value === "boolean") {
return value ? 1 : 0;
}
if(typeof value === "object") {
if(getDefinedPropertyNotOnObjectPrototype(value, "valueOf")) {
return value.valueOf();
}
if(getDefinedPropertyNotOnObjectPrototype(value, "toString")) {
return value.toString();
}
return value.valueOf();
}
};
var getDefinedPropertyNotOnObjectPrototype = function(obj, prop) {
if( obj.hasOwnProperty(prop) ) {
return obj[prop]
}
if(Object.getPrototypeOf(obj) !== Object.prototype) {
return getDefinedPropertyNotOnObjectPrototype(Object.getPrototypeOf(obj), prop);
}
}
QUnit.module("Double Equal", {});
QUnit.test("Types the same", function(){
QUnit.equal( eqeq(1,1), 1 == 1 , "1==1");
QUnit.equal( eqeq('1','1'), '1' == '1' , "'1'=='1'")
QUnit.equal( eqeq({},{}), {} == {} , "{}=={}")
QUnit.equal( eqeq(NaN,NaN), NaN == NaN , "NaN==NaN")
});
QUnit.test("Both null or undefined", function(){
QUnit.equal( eqeq(null,undefined), null == undefined , "null==undefined");
QUnit.equal( eqeq(undefined,null), undefined == null, "undefined==null");
});
QUnit.test("String == Number", function(){
QUnit.equal( eqeq(1,'1'), 1=='1' , "1=='1'");
QUnit.equal( eqeq(1,'2'), 1=='2', "1=='2'");
QUnit.equal( eqeq(1,'a'), 1=='a', "1=='a'");
QUnit.equal( eqeq('1',1), '1'==1 , "'1'==1");
QUnit.equal( eqeq('a',1), 'a'==1, "'a'==1");
});
QUnit.test("Boolean == Anything", function(){
QUnit.equal( eqeq(true,1), true==1 , "true==1");
QUnit.equal( eqeq(true,2), true==2 , "true==2");
QUnit.equal( eqeq(true,'true'), true=='true' , "true=='true'");
QUnit.equal( eqeq(true,'1'), true=='1' , "true=='1'");
QUnit.equal( eqeq(false,0), false==0 , "false==0");
QUnit.equal( eqeq(false,'false'), false=='false' , "false=='false'");
QUnit.equal( eqeq(false,'0'), false=='0' , "false=='0'");
QUnit.equal( eqeq(1,true), 1==true , "1==true");
QUnit.equal( eqeq(2,true), 2==true , "2==true");
QUnit.equal( eqeq('true',true), 'true'==true , "'true'==true");
QUnit.equal( eqeq('1',true), '1'==true , "'1'==true");
});
QUnit.test("Object == (String || Number)", function(){
QUnit.equal( eqeq(({toString: function(){return 1}}),1), ({toString: function(){return 1}})==1 , "({toString: function(){return 1}})==1");
QUnit.equal( eqeq(({toString: function(){return '1'}}),1), ({toString: function(){return '1'}})==1 , "({toString: function(){return '1'}})==1");
QUnit.equal( eqeq(({toString: function(){return true}}),1), ({toString: function(){return true}})==1 , "({toString: function(){return true}})==1");
QUnit.equal( eqeq(({valueOf: function(){return 1}}),1), ({valueOf: function(){return 1}})==1 , "({valueOf: function(){return 1}})==1");
QUnit.equal( eqeq(({valueOf: function(){return '1'}}),1), ({valueOf: function(){return '1'}})==1 , "({valueOf: function(){return '1'}})==1");
QUnit.equal( eqeq(({valueOf: function(){return true}}),1), ({valueOf: function(){return true}})==1 , "({valueOf: function(){return true}})==1");
QUnit.equal( eqeq(({toString: function(){return 1}}),true), ({toString: function(){return 1}})==true , "({toString: function(){return 1}})==true");
QUnit.equal( eqeq(({toString: function(){return '1'}}),true), ({toString: function(){return '1'}})==true , "({toString: function(){return '1'}})==true");
QUnit.equal( eqeq(({toString: function(){return true}}),true), ({toString: function(){return true}})==true , "({toString: function(){return true}})==true");
QUnit.equal( eqeq(({valueOf: function(){return 0}}),false), ({valueOf: function(){return 0}})==false , "({valueOf: function(){return 0}})==false");
QUnit.equal( eqeq(({valueOf: function(){return null}}),false), ({valueOf: function(){return null}})==false , "({valueOf: function(){return null}})==false");
QUnit.equal( eqeq(({valueOf: function(){return undefined}}),false), ({valueOf: function(){return undefined}})==false , "({valueOf: function(){return undefined}})==false");
// odd one
QUnit.equal( eqeq('a', ({valueOf: function(){return true}, toString: function(){ return 'a' }})), 'a' == ({valueOf: function(){return true}, toString: function(){ return 'a' }}) , "'a' == ({valueOf: function(){return true}, toString: function(){ return 'a' }})");
QUnit.equal( eqeq(1, [1]), 1 == [1] , "1 == [1]");
// Hard one
QUnit.equal( eqeq( "abc" , Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}}) ), "abc" == Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}}) , '"abc" == Object.create({valueOf: function(){return "abc"}}, {toString: {value: function(){ return "ABC" }}})');
});
</script>