anupama hosad
UI Engineer
Anupama H
@anuhosad
(Coercion, Equality & Relational Comparison, Hoisting)
@anuhosad
@anuhosad
[] + {}
"[object Object]"
{} + []
0
true + true
2
true / false
Infinity
false / true
0
[] * {}
NaN
{} * []
Uncaught SyntaxError: Unexpected token '*'
[] * []
0
["8"] / "2"
@anuhosad
["8","2"] / "2"
NaN
4
@anuhosad
Primitive Values
Non-Primitive Values
@anuhosad
Operator
Behaviour
<value1> + <value2>
If operands are numbers, add
If operands are strings, concatenate
All other values converted to number or string
<value1> - <value2>
Performs subtraction for number
Other values converted to number
<value1> * <value2>
Performs multiplication for number
Other values converted to number
<value1> / <value2>
Performs division for numbers
Other values converted to number
@anuhosad
@anuhosad
Argument | Result |
---|---|
undefined | NaN |
null | 0 |
boolean | true is converted to 1, false is converted to +0 |
number | no conversion necessary |
string | parse the number in the string. for example, "324" -> 324 |
object | primValue = ToPrimitive(v, hint Number) return ToNumber(primValue) |
@anuhosad
Argument | Result |
---|---|
undefined | "undefined" |
null | "null" |
boolean | true is "true", false is "false" |
string | no conversion necessary |
number | the number as a string, e.g. "1.765" |
object | primValue = ToPrimitive(v, hint String) return ToString(primValue) |
@anuhosad
Argument | Result |
---|---|
undefined | false |
null | false |
boolean | no conversion necessary |
string | "" is false, else true |
number | false if +0, -0 or NaN else true |
object | true |
@anuhosad
true + true
true / false
null + undefined
null + null
@anuhosad
"12" + 9 - 4
= 1 + 1
= 2
= 1 / 0
= Infinity
= "129" - 4
= 125
= 0 + NaN
= NaN
= 0 + 0
= 0
All these works on Primitive values
But, what if the operands are
Non-Primitive values ?
@anuhosad
ToPrimitive(input, PreferredType?)
Ref: https://www.ecma-international.org/ecma-262/5.1/#sec-9.1
@anuhosad
=> PreferredType is either Number or String, default is Number
=> Above is assuming PreferredType = Number, if PreferredType = String, steps 2 & 3 are swapped
=> If PreferredType is missing then is set to String for Date instances & to Number for all other values
var arr = [];
arr.valueOf() === arr
var obj = {};
obj.valueOf() === obj
var arr = [];
arr.toString() === ""
var obj = {};
obj.toString() === "[object Object]"
@anuhosad
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // not a primitive
},
toString: function () {
console.log("toString");
/* return the meaning of life! */
return 42;
}
};
console.log(obj * 2); // 84
var obj = { valueOf: function () { return 2 } };
console.log(6 + obj); // 8
var obj = { toString: function () { return "def" } };
console.log("abc" + obj); // abcdef
@anuhosad
[] + {}
[].toString() + {}.toString()
"" + "[object Object]"
"[object Object]"
[].valueOf() + {}.valueOf()
@anuhosad
{} + []
+[]
+""
0
Code Block
+[].toString()
Number("")
+[].valueOf()
@anuhosad
{} + {}
+{}
Code Block
+"[object Object]"
NaN
+{}.toString()
+{}.valueOf()
@anuhosad
({} + {})
"[object Object][object Object]"
Parenthesis prevents {} being treated as a code block
@anuhosad
[200] + 100
[200].toString() + 100
"200" + 100
"200100"
[200].valueOf() + 100
@anuhosad
[200] / 100
[200].toString() / 100
"200" / 100
= 2
[200].valueOf() / 100
@anuhosad
200 / 100
+[100, 200]
+[100, 200].toString()
+"100,200"
NaN
+[100,200].valueOf()
@anuhosad
[] * {}
{} * []
[] * []
[] / true
(function(){return 100}) + 100
= "function(){return 100}100"
@anuhosad
= "" * "[object Object]"
= NaN
= *[]
= Syntax Error
= "" * ""
= 0 * 0
= 0
= "" / 1
= 0 / 1
= 0
[] == 0
= true
0 == null
= false
new String("abc") == "abc"
= true
[1,2,3] == 123
= false
[123] == 123
= true
@anuhosad
new String("abc") === "abc"
= false
String("abc") === "abc"
= true
@anuhosad
1. undefined == undefined
@anuhosad
2. null == null
3. NaN != NaN
4. both objects -> compare references
5. null == undefined & undefined == null
6. string -> convert to number
7. boolean -> convert to number
8. object -> convert to primitive (hint: number)
[] == 0
= true
[].valueOf() == 0
[].toString() == 0
"" == 0
0 == 0
@anuhosad
[1,2,3] == 123
= false
ToPrimitive([1,2,3]) == 123
ToNumber("1,2,3") == 123
NaN == 123
"1,2,3" == 123
@anuhosad
[123] == 123
= true
ToPrimitive([123]) == 123
ToNumber("123") == 123
123 == 123
"123" == 123
@anuhosad
[] == ![]
= true
[] == false
0 == false
0 == 0
"" == false
@anuhosad
const a = [1, 2, 3]
const b = [1, 2, 3]
const c = "1,2,3"
console.log(a == c)
console.log(a == b)
= true
new String("abc") == "abc"
= true
0 == null
= false
@anuhosad
new String("abc") === "abc"
= false
("1,2,3" == "1,2,3")
= false
String("abc") === "abc"
= true
@anuhosad
x < y is compared as follows
@anuhosad
1. Convert the operands to primitive using ToPrimitive (hint: Number) algorithm (for whichever once is not primitive)
2. If both operands are strings, compare their character codes
3. If both operands are not strings, convert the non-string operand to number using ToNumber() algorithm and compare
"being honest" > "being encouraging"
= true
"human" < "Machine"
= false
"12" > "3"
= false
"10000" > "abc"
= false
100 > "50"
= true
@anuhosad
"human" < "machine"
= true
Hoist = raise (something) by means of ropes and pulleys
Conceptually, hoisting suggests that variable and function declarations are physically moved to the top of your code
Technically, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
@anuhosad
A function declaration is hoisted along with its definition
This lets us use it before it is declared in the code
Only variable declarations are hoisted but not their definitions
A function expression is not hoisted
Hence you cannot use it before it is declared
@anuhosad
=> function foo () {}
=> var foo = function () {};
Declaration
Expression
=> Can call before it is declared
=> Only declaration is hoisted
=> Both declaration and function body are hoisted
=> Cannot call before it is declared
@anuhosad
var a = 20;
function foo() {
console.log(a);
var a = 10;
}
foo();
Output : undefined
var a = 20;
function foo() {
var a;
console.log(a);
a = 10;
}
foo();
@anuhosad
var a = 20;
function foo() {
console.log(a);
var a = 10;
return; function a() {} }
foo();
Output : f a() {}
var a = 20;
function foo() {
var a;
function a() {}
console.log(a);
a = 10;
return;
}
foo();
@anuhosad
var a = 20;
function foo() {
console.log(a);
var a = 10;
return;
var a = function() {};
}
foo();
Output : undefined
var a = 20;
function foo() {
var a;
console.log(a);
a = 10;
return;
a = function() {};
}
foo();
@anuhosad
var a = 1; function b() { a = 10; return; } b(); console.log(a);
Output : 10
@anuhosad
var a = 1; function b() { a = 10; return; function a() {} } b(); console.log(a);
Output : 1
var a = 1; function b() { function a() {} a = 10; return; } b(); console.log(a);
@anuhosad
function parent() {
var foo = "variable";
function foo() {
return 42;
}
return foo();
}
console.log(parent());
Output : Uncaught TypeError:
foo is not a function
function parent() {
function foo() {
return 42;
}
foo = "variable";
return foo();
}
console.log(parent());
@anuhosad
function parent() {
return foo();
function foo() {
return 42;
}
var foo = "variable";
}
console.log(parent());
Output : 42
function parent() {
function foo() {
return 42;
}
var foo; // ignored
return foo();
foo = "variable";
}
console.log(parent());
@anuhosad
var abc = 0;
if (1 === 0){
function a(){
abc = 7;
}
} else if ('a' === 'a'){
function a(){
abc = 19;
}
} else if ('foo' === 'bar'){
function a(){
abc = 'foo';
}
}
a();
console.log(abc);
Output : 19
In an ES2015 environment, a function declaration inside of a block will be scoped inside that block
@anuhosad
let a = 20;
{
console.log(a);
console.log(typeof(a));
let a = 10;
}
Uncaught ReferenceError: Cannot access 'a' before initialization
Temporal Dead Zone
@anuhosad
var a = 20;
{
console.log(a);
console.log(typeof(a));
var a = 10;
}
// 20
// number
var a = 20;
function foo() {
console.log(a);
console.log(typeof(a));
var a = 10;
}
foo()
// undefined
// "undefined"
@anuhosad
Frontend Master Courses by Kyle Simpson
@anuhosad
@anuhosad
By anupama hosad