1. Data types
(1) Six data types
JavaScript has six data types: Number, String, Boolean, Null, Undefined, and Object
Except for Object, which is a reference type, the rest are primitive types (also known as primitive types). Null and Undefined are two special types
(2) Memory model
When a method is executed, a stack is created, and all variables defined in the method are placed on the stack. The stack is destroyed when the method is called
The stack holds the value of the primitive type and the reference variable of the reference type. The value of the reference variable points to the address of the object in the heap memory
When an object is created, reference variables are stored in the stack, and the object itself is stored in the heap, meaning that the object is not destroyed when the method call ends
In fact, the destruction of objects is determined by the garbage collection mechanism and is only destroyed if the object is not referenced by any reference variable
(3) Pass by value
All function parameters are passed by value in JavaScript, but some interesting behavior can occur due to the memory model
- When we modify a base variable in a function, we do not modify the value passed in
- When we modify a reference variable in a function, we modify the value passed in (think about why, as explained by the memory model)
let number = 123 // Basic type
let object = { // Reference type
name: 'Steve'.age: 18
}
function changeNumber(num) {
num = 456
}
function changeObject(obj) {
obj.age = 20
}
changeNumber(number)
changeObject(object)
console.log(number)
console.log(object.age)
/* * Result: * 123 * 20 **/
Copy the code
2. Type detection
(1) the typeof
Used to detect the typeof a variable. Note that for null and array variables, typeof returns object
In addition, typeof returns object for almost any typeof object, meaning that typeof cannot be used to determine exactly what type an object is
let a = 0
let b = 'hello'
let c = true
let d = null
let e = undefined
let f = {}
let g = []
let h = function(){}
console.log('a: ' + typeof a)
console.log('b: ' + typeof b)
console.log('c: ' + typeof c)
console.log('d: ' + typeof d)
console.log('e: ' + typeof e)
console.log('f: ' + typeof f)
console.log('g: ' + typeof g)
console.log('h: ' + typeof h)
* a: number * b: string * C: Boolean * d: object * e: undefined * f: object * g: object * h: function **/
Copy the code
(2) the Object. The prototype. ToString. Call ()
Used to detect the typeof a variable. Typeof cannot detect null and array
let a = 0
let b = 'hello'
let c = true
let d = null
let e = undefined
let f = {}
let g = []
let h = function(){}
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1)}console.log('a: ' + typeOf(a))
console.log('b: ' + typeOf(b))
console.log('c: ' + typeOf(c))
console.log('d: ' + typeOf(d))
console.log('e: ' + typeOf(e))
console.log('f: ' + typeOf(f))
console.log('g: ' + typeOf(g))
console.log('h: ' + typeOf(h))
/* * Result: * a: Number * b: String * C: Boolean * D: Null * E: Undefined * f: Object * G: Array * h: Function **/
Copy the code
(3) instanceof
It is used to determine whether an instance belongs to a certain type and can solve the problem that Typeof cannot accurately determine object types
var Message = function(descrition) { // constructor
this.detail = descrition
}
let message = new Message('Hello')
let object = new Object(a)console.log(message instanceof Message)
console.log(message instanceof Object)
console.log(object instanceof Message)
console.log(object instanceof Object)
console.log(Message instanceof Object)
/* * Result: * true * true * false * true * true **/
Copy the code
Instanceof works by determining whether the prototype of the right object exists in the prototype chain of the left object
Once we understand how this works, we can implement an Instanceof ourselves
function myInstanceOf(left, right) {
let lValue = left.__proto__
let rValue = right.prototype
while (true) {
if (lValue === null) return false
if (lValue === rValue) return true
lValue = lValue.__proto__
}
}
Copy the code
3. Type conversion
(1) Cast type
① String -> Number: parseInt(String [, radix]) & parseFloat(String)
ParseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt parseInt ParseFloat is used to parse strings into floating point numbers
Both parse from the first non-space character to the end of the string or to an invalid numeric character
If parsing succeeds, a number is returned; NaN is returned if the first non-space character is not a number or symbol
let a = parseInt(' 123abc')
let b = parseFloat(' 123.456abc')
console.log(a)
console.log(b)
/* * Result: * 123 * 123.456 **/
Copy the code
② Any -> Number: Number()
The conversion rules are as follows:
value | Transformation rules |
---|---|
Number | Direct output |
String | If the string is empty, it is converted to 0 if the string contains a valid integer format, it is converted to decimal if the string contains a valid floating-point format, it is converted to hexadecimal otherwise, it is converted to NaN |
Boolean | If true, convert to 1 and if false, convert to 0 |
Null | Converted to 0 |
Undefined | Converted to NaN |
Object | Call the Object’svalueOf() Method to convert to NaN according to the above rules, call Object’stoString() Method is converted according to the above rules |
let a = Number(123)
let b = Number('456')
let c = Number(true)
let d = Number(false)
let e = Number(null)
let f = Number(undefined)
let g = Number(new Date())
let h = Number(new Array())
console.log(a)
console.log(b)
console.log(c)
console.log(d)
console.log(e)
console.log(f)
console.log(g)
console.log(h)
/* * Result: * 123 * 456 * 1 * 0 * 0 * NaN * 1578556849729 * 0 **/
Copy the code
③ Any -> String: String()
The conversion rules are as follows:
value | Transformation rules |
---|---|
Number | Convert to a numeric value |
String | Direct output |
Boolean | If true, convert to true and if false, convert to false |
Null | Converts a null |
Undefined | Convert undefined |
Object | Convert according to specific rules |
let a = String(123)
let b = String('asdf')
let c = String(true)
let d = String(false)
let e = String(null)
let f = String(undefined)
let g = String({})
let h = String([123.'asdf'.true.false.null.undefined])
console.log(a)
console.log(b)
console.log(c)
console.log(d)
console.log(e)
console.log(f)
console.log(g)
console.log(h)
/* * Result: * 123 * asdf * true * false * null * undefined * [Object object] * 123, ASdf,true,false,, **/
Copy the code
(2) Automatic type conversion
① Conditional judgment
In the condition judgment, the value of the variable will be automatically converted into a Boolean value according to the following rules:
value | Transformation rules |
---|---|
Number | 0, NaN is converted to false and the rest is converted to true |
String | The empty string is converted to false and the rest is converted to true |
Null | Converted to false |
Undefined | Converted to false |
Object | Converted to true |
let a = 123
let b = ' '
let c = null
let d = undefined
let e = {}
a ? console.log('true') : console.log('false')
b ? console.log('true') : console.log('false')
c ? console.log('true') : console.log('false')
d ? console.log('true') : console.log('false')
e ? console.log('true') : console.log('false')
/* * Result: * true * false * false * false * true **/
Copy the code
② Numerical operation
-
For the + operator, the conversion rules are as follows:
If none of the operands are strings or objects, they are converted to Number by the Number() function
If the operand contains a String or object, it is converted to String by the String() function
let a = 1 + true
let b = 1 + null
let c = 1 + undefined
let d = '1' + true
let e = '1' + null
let f = '1' + undefined
let g = '1' + 1
let h = {} + true
let i = [] + false
console.log(a)
console.log(b)
console.log(c)
console.log(d)
console.log(e)
console.log(f)
console.log(g)
console.log(h)
console.log(i)
/* * Result: * 2 * 1 * NaN * 1true * 1NULL * 1undefined * 11 * [object object]true * false **/
Copy the code
- for
-
,*
,/
,%
Operator, all pass firstNumber()
The function is converted to a number and then evaluated
Based on the implicit conversion rule of numerical operation, we can get a convenient shortcut to convert numbers and strings
// number -> string
let number = 123
let string = number + ' '
console.log(typeof string)
console.log(string)
/* * Result: * string * 123 **/
Copy the code
// string -> number
let string = '123'
let number = string - 0
console.log(typeof number)
console.log(number)
/* * Result: * number * 123 **/
Copy the code
③ Equal operation
When using the == operator to compare whether two variables are equal, if the variables are of different types, an implicit conversion is performed before the comparison, as follows:
The order | Variable 1 | The variable 2 | operation |
---|---|---|---|
1 | NaN | * | Returns false |
2 | Null | Undefined | Returns true |
3 | Null | Null | Returns true |
4 | Undefined | Undefined | Returns true |
5 | Null | Except Null, Undefined | Returns false |
6 | Undefined | Except Null, Undefined | Returns false |
7 | Boolean | * | Convert Boolean to Number for comparison |
8 | Object | Object | Two objects are equal only if they point to the same memory address |
9 | Object | Number, a String, | After converting Object to its original value (Number/String), comparison is used firstvalueOf() Method returns the result if the object can be converted to its original value otherwisetoString() Method returns the result if the object can be converted to its original value, otherwise thrownTypeError abnormal |
10 | Number | Number | A direct comparison |
11 | String | String | A direct comparison |
12 | String | Number | Convert String to Number and compare |
Practice some questions:
false= =0 // true
false= ='0' // true
false= = []// true
false= = {}// false
123= = [123] // true
2= = {valueOf(){ return 2 }} // true
1= = {valueOf: function(){ return[]},toString: function(){ return 1 }} // true
Copy the code
Because of the implicit conversion when using == for judgment, === is commonly used in projects
4. Assignment, shallow copy and deep copy
For primitive types, assignment, shallow copy, and deep copy copy the value of the old variable to the new variable
let number = 159
let string = 'hello'
let number_copy = number
let string_copy = string
number_copy = 258
string_copy = 'hi'
console.log('number: ' + number) // The value of the original variable does not change
console.log('string: ' + string) // The value of the original variable does not change
console.log('number_copy: ' + number_copy)
console.log('string_copy: ' + string_copy)
/* * Result: * number: 159 * string: hello * number_copy: 258 * string_copy: hi **/
Copy the code
For reference types:
- After the assignment, the old and new variables point to the same memory address. Changing the new variable will affect the value of the old variable
let object = { first_name: 'Steve'.last_name: 'Jobs' }
let array = [1.3.5]
let object_copy = object
let array_copy = array
object_copy['first_name'] = 'Steven'
array_copy[0] = 2
console.log('object["first_name"]: ' + object['first_name']) // The value of the original variable has changed
console.log('array[0]: ' + array[0]) // The value of the original variable has changed
console.log('object_copy["first_name"]: ' + object_copy['first_name'])
console.log('array_copy[0]: ' + array_copy[0])
/* * Result: * object["first_name"]: Steven * array[0]: 2 * object_copy["first_name"]: Steven * array_copy[0]: 2 **/
Copy the code
- A shallow copy of a new variable assigns the first layer of data from the old variable to the new variable
// Common shallow copy methods for objects are object.assign
// Common shallow copy methods for arrays are array. from, slice, concat
let object = {
name: {
first_name: 'Steve'.last_name: 'Jobs'
},
age: 18
}
let array = [[1.3].5.7]
let object_shallow_copy = Object.assign({}, object)
let array_shallow_copy = Array.from(array)
object_shallow_copy['name'] ['first_name'] = 'Steven'
object_shallow_copy['age'] = 20
array_shallow_copy[0] [0] = 2
array_shallow_copy[2] = 11
console.log('object["name"]["first_name"]: ' + object['name'] ['first_name'])
console.log('object["age"]: ' + object['age'])
console.log('array[0][0]: ' + array[0] [0])
console.log('array[2]: ' + array[2])
console.log('object_shallow_copy["name"]["first_name"]: ' + object_shallow_copy['name'] ['first_name'])
console.log('object_shallow_copy["age"]: ' + object_shallow_copy['age'])
console.log('array_shallow_copy[0][0]: ' + array_shallow_copy[0] [0])
console.log('array_shallow_copy[2]: ' + array_shallow_copy[2])
/ execution results: * * * object (" name "] [" first_name "] : Steven * object [] "age" : 18 * array [0] [0] : 2 * array [2] : 7 * object_shallow_copy["name"]["first_name"]: Steven * object_shallow_copy["age"]: 20 * array_shallow_copy[0][0]: 2 * array_shallow_copy[2]: 11 **/
Copy the code
Implement a shallow copy function yourself:
function shallowCopy(object) {
if (typeofobject ! = ='object') return
let newObject = object instanceof Array ? [] : {}
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key]
}
}
return newObject
}
Copy the code
- All data of the old variable (no matter how deeply nested) is copied to the new variable. The old and new variables do not affect each other
Parse (json.stringify ())) is the easiest way to do this, but it has some drawbacks
// If the attribute has undefined, NaN, Infinity, function, then it will be converted to null
// If there are RegExp or Error objects in the property, they will be converted to empty objects
let object = {
name: {
first_name: 'Steve'.last_name: 'Jobs'
},
age: 18
}
let array = [[1.3].5.7]
let object_deep_copy = JSON.parse(JSON.stringify(object))
let array_deep_copy = JSON.parse(JSON.stringify(array))
object_deep_copy['name'] ['first_name'] = 'Steven'
object_deep_copy['age'] = 20
array_deep_copy[0] [0] = 2
array_deep_copy[2] = 11
console.log('object["name"]["first_name"]: ' + object['name'] ['first_name'])
console.log('object["age"]: ' + object['age'])
console.log('array[0][0]: ' + array[0] [0])
console.log('array[2]: ' + array[2])
console.log('object_deep_copy["name"]["first_name"]: ' + object_deep_copy['name'] ['first_name'])
console.log('object_deep_copy["age"]: ' + object_deep_copy['age'])
console.log('array_deep_copy[0][0]: ' + array_deep_copy[0] [0])
console.log('array_deep_copy[2]: ' + array_deep_copy[2])
/ execution results: * * * object (" name "] [" first_name "] : Steve * object [] "age" : 18 * array [0] [0] : 1 * array [2] : 7 * object_deep_copy["name"]["first_name"]: Steven * object_deep_copy["age"]: 20 * array_deep_copy[0][0]: 2 * array_deep_copy[2]: 11 **/
Copy the code
Implement a deep-copy function yourself:
Note that this simple implementation still has some drawbacks
function deepCopy(object) {
if (typeofobject ! = ='object') return
let newObject = object instanceof Array ? [] : {}
for (let key in object) {
if (object.hasOwnProperty(key)) {
let item = object[key]
newObject[key] = typeof item === 'object' ? deepCopy(item) : item
}
}
return newObject
}
Copy the code