leBlock: {
let x = 1
for (;;) {
log("outer loop")
for (;;) {
log("inner loop")
break leBlock
}
}
}
outer loop
inner loop
- Undefined, Null
- Boolean, String, Number
- Object
Therefore, constructors technically don’t introduce new types, even though
they are said to have instances.
- Compared by value: the content is compared
- Always immutable: properties can't be changed, added, or removed
- All non-primitive values are objects
- Types
- Plain Objects
- Arrays
- Regular Expressions
- Compared by reference
- Mutable by default
- undefined and null
- 0
- NaN
- ''
"abc".charAt === String.prototype.charAt true
String.prototype.hello = () => log("hello")
"abc".hello() hello
Technically, primitive values do not have their own properties, they borrow
them from wrapper constructors. But that is something that goes on behind the
scenes, so you don’t normally see it.
the + operator examines its operands. If one of them is a string, the other is
also converted to a string and both are concatenated, Otherwise, both operands
are converted to numbers (see Converting to Number) and added:
"foo" + 3 'foo3'
3 + true 4
The typeof operator distinguishes primitives from objects and determines the
types of primitives.
The instanceof operator determines whether an object is an instance of a given
constructor.
- str.substr( beginIndex [, length] ) takes optionsl string length
- str.slice( beginIndex [, endIndex] ) takes optional end index
- Extract single character with str[0] or str.charAt(0)
- str.split( [separator [, limit] ])
- If separator is undefined split returns entire string (seems useless)
- If separater is '' returns array of every character.
- Can be a regex
- If regex has groups the matches are included, shown below
let strA = "a,b.c|d,e.f|"
let a = strA.split(/([,.\|])/)
log(a) [ 'a', ',', 'b', '.', 'c', '|', 'd', ',', 'e', '.', 'f', '|', '' ]
let strB = a.join("")
log(strB) 'a,b.c|d,e.f|'
log(strA === strB) true
- ' abc'.trim() removes whitespace from beginning and end.
- str.toLowerCase()
- str.toUpperCase()
- str.concat(str [, str2 [, str3]])
- 'abc'.concat() results in 'abcundefined' if x is undefined, so make sure
its initiated with x=''
- str.indexOf(searchStr, position=0)
- Returns position if found, -1 if nothing found.
- searchStr cannot a regex
- case sensitive
- /b/.test(str) is better than str.indexOf('b') >=0
- str.search(regex)
- Like indexOf returns position of first match or -1
- Will convert string parameter to regex
- Unlike indexOf doesn't take an position
log("abc".indexOf("b") >= 0) true
log(/b/.test("abc")) true
log("abc".search(/b/)) 1
log("abc".search("b")) 1
log("abc".search(/B/)) -1
- str.match(regex)
- Like str.search() takes or converts regex argument
- Capture groups or return all matching substrings
- Returns match group if no /g flag
- Returns array of all matches if /g set
- str.replace(regexp|substr, newSubstr|function)
- If first argument is a string it is NOT interpreted as a regex, unlike
match() and search()
- Unless first argument is a regex/g it will only replace first match
- The replacement function parameters are complicated, but the first position
is the match value
- The replacement string can contain patters starting with $
- $$ inserts a $
- $& inserts the matched substring
- $` Inserts the portion of the string that precedes the matched substring.
- $' Inserts the portion of the string that follows the matched substring.
- $n Where n is a positive integer less than 100, inserts the nth
parenthesized submatch string, provided the first argument was a RegExp object.
Note that this is 1-indexed.
log("abc".match(/B/)) null
log("abc".match(/b/)) [ 'b', index: 1, input: 'abc' ]
log("abc".match("b")) [ 'b', index: 1, input: 'abc' ]
log("abc".match(/b/g)) [ 'b' ]
log("abcbc".match(/b/g)) [ 'b', 'b' ]
log("abc".replace("a", "A")) Abc
log("abc".replace(/a/, "A")) Abc
log("abcabc".replace(/a/, "A")) Abcabc
log("abcabc".replace(/a/g, "A")) AbcAbc
"abc".replace(/a/, x => log(`found ${x}`)) found a
"abc".replace(/(a)/, (x, p1, offset, whole) => {
log(`found ${x} ${p1} ${offset} ${whole}`)
}) found a a 0 abc
let i = 0,
a = []
do {
a.push(i++)
} while (i < 10)
log(a) [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
- iterates over indices not values, so we just get 0,1,2,3,4...
- iteration includes properties added to array
- use [].forEach instead of for-in for arrays
- iterates over all enumerable properties, including inherited ones
- evaluates expression and jumps to matching cases, finding it using ===
- case can be an expression
- cases are fall through, so you need to break
- Use fallthrough to combine multple cases
switch ("red") {
case "blue":
log("color is blue")
break
case ["r", "e", "d"].join(""):
log("color is red")
break
default:
log("not found")
} color is red
switch ("red") {
case "red":
case "white":
case "blue":
log("color is american")
break
default:
log("unamerican")
} color is american
let x = 10000
switch (true) {
case x < 10:
log("small number")
break
case x < 100:
log("sizable number")
break
case x < 1000:
log("big number")
break
default:
log("huge number")
}
JavaScript has special constructors for exception objects . Use those or
subclass them. Their advantage is that JavaScript automatically adds a stack
trace (on most engines) and that they have room for additional context-specific
properties. The simplest solution is to use the built-in constructor Error():
When Error is used like a function -- without new, it will return an Error
object. Therefore, a mere call to Error will produce the same output that
constructing an Error object via the new keyword would.
Optional finally clause, it is always called, even if try has a return statement.
Can be used for function cleanup.
try {
throw Error("help")
} catch (e) {
log("caught ", e.stack)
} finally {
log("always")
}
- But the name can only be accessed within the function itself
- Not sure if f.name property is reliably supported in this situation.
let f = function me() {
console.log(me)
}
f() [Function: me]
console.log(me) ReferenceError: me is not defined
console.log(f.name) f
!!(function() {
console.log("hi")
})() hi
let o = {a: 1}
delete o.a
log(o) {}
var obj = new Object()
var obj = {}
let o = {
x: 1,
add: function(x) {
return x + 1
}
}
let a1 = o.add.bind(o)
log(a1(3)) 4
C.prototype = {
method1: function() {}
}
C.prototype.method1 = function() {}
C.prototype = {
constructor: C,
method1: function() {}
}
function Constructor() {
let data = []
this.fun = function() {
data
}
}
function Singleton() {
if (Singleton.inst) {
return Singleton.inst
} else {
Singleton.inst = this
}
this.random = Math.random()
}
let o = function() {
let instance
return {
getInstance: function() {
if (!instance) {
instance = {n: Math.random()}
}
return instance
}
}
}
let o2 = o()
log(o2.getInstance())
let o = function() {
function f() {}
return {f}
}
let o = {
length: 3,
0: "a",
1: "b",
2: "c"
}
let v = Array.prototype.map.call(o, x => x)
log(v) [ 'a', 'b', 'c' ]
var dict = Object.create(null)
a = [1, 2, 3][(1, 2, 3)]
delete a[1] bad!
a [ 1, <1 empty item>, 3 ]
log(Array.isArray([])) true
let a = []
a.push(1, 2, 3)
log(a) [ 1, 2, 3 ]
a.push(...[4, 5, 6])
log(a) [ 1, 2, 3, 4, 5, 6 ]
a = a.concat([7, 8, 9])
log(a) [ 1, 2, 3, 4, 5, 6 ]
console.time("a")
for (let i = 0; i < 1000; i++) {}
console.timeEnd("a") a: 0.305ms
let str = "abc123"
let re = /(a)/g
log(re.exec(str)) [ 'a', 'a', index: 0, input: 'abc123' ]
log(re.exec(str)) null