JS has typed values, not typed variables Built-in types:
- Strings
- Number
- Boolean
- Null and undefined
- Object
- Symbol
let a;
a = 23 // typeof a // “number”
a = ‘hello’ // typeof a // “string”
a = undefined // typeof a // “undefined”
a = true // typeof a // boolean
a = null // typeof a //object —> weird
a = { name : ‘Jon’ } //typeof a object
Return value from typeof is always one of above 7 in the list. The value returned is always a string. So:
a = “Meera”
typeof a is “string” and not string
a = 45
typeof a is “number” and not just number
So, *typeof typeof a* is always **string**
Only values have types in JS, variables are simply containers.
let obj = {
a : “hello”,
b: 45,
c : true
}
obj.a //“hello”
obj.b //45
obj.c //true
obj[“a”] //“hello”
obj[“b”] // 45
obj[“c”] // true
let b = “a”
obj[b] //“hello”
obj[“b”] //45
Arrays Arrays are objects that hold values of any type. Numerically indexed.
let arr = [“hello”, 45, true]
typeof arr // ‘object’
arr.length //3
Functions
function foo(){
return 42
}
foo.bar = “hello world”
typeof foo // function
typeof foo() //number
typeof foo.bar //string
JS natives and boxing
let a = “hello” // string primitive
let b = 3.14159 // number primitive
a.length // 5
a.toUpperCase() // “HELLO”
b.toFixed(4) //3.1416
The variable b is not an object. So, how does the method toUpperCase() work on a primitive type of string?
There is a String (capital S) object wrapper form, usually called a native, it pairs with the primitive string
type. The String object wrapper defines the toUpperCase() method in its prototype. JS automatically boxes
the primitive value to its object wrapper counterpart when we do something like ”hello”.toUpperCase()
- string value -> wrapped by String object
- number value -> wrapped by Number object
- boolean value -> wrapped by Boolean object
Result of any comparison is strictly boolean
Coercion
explicit coercion
let a = ’42’
let b = Number(a)
a // “42”
b // 42
implicit coercion
let a = ’42’
let b = a - 1 // “42” is implicitly coerced to number 42 here
a // ’42’
b // 41 —> number
Truthy & Falsy When a non-boolean value is coerced into boolean, does it become true or false?
Falsy values in JS:
- “” (Empty string)
- 0, -0, NaN
- null, undefined
- false
Truthy values in JS:
- “Hello”
- 42
- true
- [ ], [1, 2, 3] (arrays)
- { }, { a: 42 } (objects)
- function foo {}
Equality
== and ===
== checks for value equality with coercion allowed. === checks for value equality without coercion allowed. Called strict equality.
let a = “42”
let b = 42
a == b // true. -> Is “42” (a) coerced as 42. Or, is 42 (b) coerced as “42” ? Answer “42” becomes 42.
a === b // false
Equality with objects (or arrays & functions) - Will check for equality of reference not values. Arrays are by default coerced to strings with commas in the middle.
let a = [1, 2, 3]
let b = [1, 2, 3]
let c = “1,2,3”
a == c // true
b == c // true
a == b // false !!!
Inequality
- Applies to numbers obviously 3 < 4
- Also applies to string “bar” < “foo”
Coercion
let a = 43
let b = “42”
let c = “41”
let x = “foo”
a > b //true
b > c //true
a > c // true
a > x // false
x > a // false
a == x // false
x is coerced into the invalid number value NaN in the < and > comparisons . NaN is neither greater than nor lesser than any value The == comparison is different. Becomes: 43 == NaN, which is not true
- Usual rules apply to variable naming convention
- must start with a-z, A-Z,$, _
- can contain 0-9
- reserved words: for, in, if, null, true, false etc. Function Scopes Hoisting When a var appears inside a scope, that declaration is taken to belong to entire scope and accessible throughout the scope
var a = 3
foo() // function foo is recognized as it is hoisted
function foo(){
a = 2
console.log(a) // 2
}
console.log(a) // 2
Global scope a
is changed everywhere in the above code.
var a = 3
foo() // function foo is recognised even before declaration, as it is hoisted
function foo(){
a = 2
console.log(a) // 2
var a // this is hoisted two lines above, to the top of foo
}
console.log(a) // 3 -> This is the global `a`, not affected by the function scope foo, since foo has its own copy of `a`
It is not a good idea to do variable hoisting, it is confusing. More common to do function hoisting (foo). My note: I think much of this is mitigated with ES6 and arrow functions.
Nested Scopes When a variable is declared, it is available anywhere in the scope. ( declaration using var only) ES5
function foo() {
var a = 1
function bar(){
var b = 2
function baz(){
var c = 3
console.log(a, b, c) // 1, 2, 3
}
baz()
console.log(a, b) // 1, 2
}
bar()
console.log(a) // 1
}
foo()
- if-else
- switch
- ternary operator condition? true : false
Undeclared variables are automatically globally declared and available in ES5. For eg:
function foo() {
a = 1 // undeclared
}
foo()
console.log(a) //1. the variable a is available globally.
This is undesirable. In strict mode, this is mitigated:
“use strict”
function foo(){
a = 1 //undeclared
}
foo()
console.log(a) // reference error, a is not defined