[JS Series 2] Type and syntax

[JS Series 2] Type and syntax

Type and syntax

Types of

Built-in type

  • null
  • undefined
  • boolean
  • number
  • string
  • object
  • symbol
typeof undefined === "undefined";//true typeof true === "boolean";//true typeof 42 === "number";//true typeof "42" === "string";//true typeof {life: 42} === "object";//true //object subtype typeof function a () {} === "function"//true typeof [1, 2, 3] === "object"//true //New types added in ES6 typeof Symbol() === "symbol";//true //The above six have the same name string corresponding to it //null special typeof null === "object"//true Copy code

Value and type

Variables have no type. When using typeof to manipulate variables, it is an operation on the value held by the variable.

undefined&undeclared

Undefined is a kind of value, and undeclared means that the variable has not been declared.

var a a//undefined b//Uncaught ReferenceError: b is not defined typeof a//undefined typeof b//undefined Copy code

typeof defense mechanism

Especially multiple script files share the global namespace to load variables

  • Judge undeclared variables

    //will report an error //Uncaught ReferenceError: DEBUG is not defined if (DEBUG) { console.log("DEBUG is starting") } Copy code
    • typeof
    if (typeof DEBUG !== "undefined") { console.log("DEBUG is starting") } Copy code
    • window
    if (window.DEBUG) { console.log("DEBUG is starting") } Copy code

value

Array

tips

  • delete can delete the array, but does not change the length
  • Create a "sparse array" (an array containing blank or vacant cells), the undefined of the vacant cell is different from the undefined of the display assignment
  • Arrays are indexed by numbers, and the index is also an object, so it can contain string keys and attributes. If the string key value can be coerced into a decimal array, it will also be treated as a numeric index.
var a = [] a[0] =1 a['footer'] = 2 console.log(a.length)//1 console.log(a['footer'])//2 console.log(a.footer)//2 a['13'] = 14 console.log(a.length)//14 Copy code

Array-like

A set of values that can survive a numeric index, such as: DOM element list returned by DOM query operation, access to function parameters as a list through the arguments object

  • Array-like conversion to array
function foo () { console.log(arguments)//{"0":"bar","1":"baz","2":"bam"} let arr = Array.prototype.slice.call(arguments) console.log(arr)//["bar","baz","bam"] } let obj = {} foo.apply(obj, ['bar','baz','bam']) Copy code
  • ES6 Array.from

String

To some extent, a string can be said to be an array-like, with length, indexof, and concat. However, strings in JS are immutable, and arrays are mutable. Therefore, the string cannot "borrow" the variable member function of the array, such as reverse

digital

Integer

"Integer" is a decimal number without decimals

console.log (42.0 === 42)//true copy the code

Number method

var a = 42.59; a.toPrecision( 1 );//"4e+1" a.toPrecision( 2 );//"43" a.toPrecision( 3 );//"42.6" a.toPrecision( 4 );//"42.59" a.toPrecision( 5 );//"42.590" a.toPrecision( 6 );//"42.5900" //Invalid syntax: 42.toFixed( 3 );//SyntaxError 42. to be regarded as part //The following syntaxes are all valid: (42).toFixed( 3 );//"42.000" 0.42.toFixed( 3 );//"0.420" 42..toFixed( 3 );//"42.000" Copy code

Support format

Binary, octal, hexadecimal

0xf3;//243 hexadecimal 0Xf3;//Same as above 0o363;//243 in octal 0O363;//Same as above 0b11110011;//243 binary 0B11110011;//Same as above Copy code

0.1+0.2 === 0.3

The "machine precision" of JS: 2^-52. In ES6, this value is defined in Number.EPSILON, which can be used to compare whether two numbers are equal.

function numberCloseToEqual (a, b) { return Math.abs(a-b) <Number.EPSILON } let a = 0.1 + 0.2 let b = 0.3 console.log(numberCloseToEqual(a, b))//true console.log(numberCloseToEqual(0.000000001, 0.000000000002))//false Copy code

Safe range of integers

The way of digital presentation determines that the safety range of "integer" needs to be much smaller than Number.Max_value (1.7976931348623157e+308). The largest integer that can be presented "safely" is 2^53-1, which is defined in ES6 as

Macth.MAX_SAFE_INTEGER
, The corresponding minimum integer bit
Number.MIN_SAFE_INTEGER
.

Integer detection

  • Number.isInteger() in ES6

    function print(val) { console.log(val) } print(Number.isInteger( 42 ))//true print(Number.isInteger( 42.000 ))//true print(Number.isInteger( 42.3 ))//false Copy code

    Implement Number.isInteger() for versions before ES6

    if (!Number.isInteger) { Number.isInteger = function (number) { return typeof number ==='number' && number% 1 == 0 } } Copy code
  • Check if it is a safe integer

Number.isSafeInteger(...), one more judgment than Number.isInteger that is not greater than the maximum safe value

32-bit signed integer

All bitwise operators are only applicable to 32-bit numbers, the safe range of numbers under this operation becomes

Math.pow(-2, 31)~Math.pow(2, 31)
;Such as: |, &, <<, >> bitwise operators in detail

Special value

Value that is not a value

The undefined type has only one value, which is undefined. The null type also has only one value, which is null. Their names are both types and values.

Undefined and null are often used to denote "empty" values or "not a value" values. There are some subtle differences between the two. E.g:

  • null refers to empty value (empty value)
  • undefined means missing value

or:

  • undefined means never assigned
  • null means that a value has been assigned, but there is currently no value

Null is a special keyword, not an identifier, and we cannot use it as a variable and assign a value. However, undefined is an identifier that can be used and assigned as a variable.

void

Under normal circumstances, you can pass

void 0
To get
undefined

Special number

  • NaN can be understood as'invalid value' or'failed value'.

    typeof NaN ==='number'
    Is true;
    NaN == NaN
    Is false.

    • You can use the global isNaN() to check whether it is NaN, but in fact the check result is not accurate. In fact, isNaN() checks whether the parameter is not NaN, nor is it a number.
    window.isNaN(NaN)//true window.isNaN('foo')//true window.isNaN(2)//false Copy code
    • ES6 can use Number.isNaN()
    Number.isNaN(NaN)//true Number.isNaN('foo')//false Number.isNaN(2)//false Copy code

    Built-in implementation method

    if (!Number.isNaN) { Number.isNaN = function (n) { return n !== n } } Copy code
  • Infinite number

Number.POSITIVE_INFINITY
Number.NEGATIVE_INFINITY

console.log(1/0, -1/0)//Infinity,-Infinity console.log(Infinity/Infinity)//NaN Copy code
  • Zero value

Simple scalar basic type values (strings and numbers, etc.) are assigned/passed by value copying, while compound values (objects, etc.) are assigned/passed by reference copying. References in JavaScript are different from references/pointers in other languages. They cannot point to other variables/references, but only point to values.

Native function

  • Commonly used native functions:

String() Number() Boolean() Array() Object() Function() RegExp() Date() Error() Symbol()

let a = new String('abc')//Create an encapsulated object of the string'abc' instead of the basic type value'abc' console.log(a) //String {"abc"} 0: "a" 1: "b" 2: "c" length: 3 __proto__: String [[PrimitiveValue]]: "abc" console.log(typeof a)//object console.log(a instanceof String)//true console.log(Object.prototype.toString.call(a))//[object String] Copy code

Internal attributes [[class]]

All objects (such as arrays) whose typeof return value is "object" contain an internal property [[Class]], but this property cannot be accessed directly, and is generally viewed through Object.prototype.toString().

Object.prototype.toString.call( [1,2,3] );//"[object Array]" Object.prototype.toString.call(/regex-literal/i );//"[object RegExp]" Object.prototype.toString.call( null );//"[object Null]" Object.prototype.toString.call( undefined );//"[object Undefined]" Object.prototype.toString.call( "abc" );//"[object String]" Object.prototype.toString.call( 42 );//"[object Number]" Object.prototype.toString.call( true );//"[object Boolean]" Copy code

The value of [[Class]] property inside the array is Array, and the value of regular expression is RegExp.

Although native constructors such as Null() and Undefined() do not exist, the internal [[Class]] property values are still "Null" and "Undefined".

Packaging Object Packaging

JS will automatically wrap a package object for the basic type value

Encapsulation object explanation

console.log(new Boolean(false)) if (new Boolean(false)) {//will be executed console.log(1) } Copy code

Unpack

If you want to get the basic type value in the encapsulated object, you can use the valueOf() function:

var a = new String( "abc" ); var b = new Number( 42 ); var c = new Boolean( true ); a.valueOf();//"abc" b.valueOf();//42 c.valueOf();//true Copy code

Implicit split (forced type conversion):

var a = new String( "abc" ); var b = a + "";//the value of b is "abc" typeof a;//"object" typeof b;//"string" Copy code

Forced type conversion

It can be distinguished as follows: Type conversion occurs in the compilation phase of statically typed languages, while forced type conversion occurs at runtime of dynamically typed languages.

Abstract value operations

ToString

  • For ordinary objects, unless you define your own, toString() (Object.prototype.toString()) returns the value of the internal property [[Class]], such as "[object Object]". If the object has its own toString() method, it will be called when stringified and its return value will be used.

  • The default toString() of the array call has been redefined. After stringizing all the units, use "," to connect them, such as:

var a = [1, 2, 3] console.log(a)//"1, 2, 3" Copy code

Tips: JSON stringification

  • JSON.stringify() is the same as ToString
    • The JSON.stringify(..) rules for strings, numbers, booleans, and null are basically the same as ToString.
    • If the toJSON() method is defined in the object passed to JSON.stringify(..), this method will be called before stringification to convert the object into a safe JSON value.

All safe JSON values (JSON-safe) can be stringified using JSON.stringify(..). A safe JSON value is a value that can be presented in a valid JSON format.

  • Unsafe JSON value

undefined, function, symbol (ES6+), and objects that contain circular references (references between objects to form an infinite loop). JSON.stringify(..) automatically ignores undefined, function, and symbol in the object, and returns null in the array (to ensure that the unit position is unchanged).

  • The toJSON method is defined in the object. When JSON is stringified, this method will be called first, and then its return value will be used for serialization.

ToNumber

When the processing fails, NaN is returned, and the hexadecimal data is processed in decimal.

Binary: 0b/0B; Octal: 0o/0O; Hexadecimal: 0x/0X

var a = { valueOf: function(){ return "42"; } }; var b = { toString: function(){ return "42"; } }; var c = [4,2]; c.toString = function(){ return this.join( "" );//"42" }; Number( a );//42 Number( b );//42 Number( c );//42 Number( "" );//0 Number( [] );//0 Number( ["abc"] );//NaN let num = '0x123' console.log(Number(num))//291 Copy code

ToBoolean

  • False value
    • undefined
    • null
    • false
    • +0, -0, and NaN
    • ''

ToPrimitive

In order to convert the value to the corresponding basic type value, the abstract operation ToPrimitive (see ES5 specification section 9.1) will first (through the internal operation DefaultValue, see ES5 specification section 8.12.8) to check whether the value has a valueOf() method. If it has and returns a basic type value, use that value to perform a coercion. If not, use the return value of toString() (if it exists) to perform the coercion.

If neither valueOf() nor toString() returns a basic type value, a TypeError error will be generated.

Show coercion

  • Number, String
  • Unary operators +,-

Common operations available

  • Date display converted to number
    var timestamp = +new Date() var timestamp = new Date().getTime(); //var timestamp = (new Date()).getTime(); //var timestamp = (new Date).getTime(); //Best Es5 var timestamp = Date.now() Copy code
  • ~ Operator

The binary operators mentioned above,Also one of them. EncounterWhen the value is first forced to a 32-bit number, and then perform the word bit operation "not" (flip each character)

~X is roughly equivalent to -(x+1)

~ @ 42 - (42 + 1) ===> -43 copy the code

Next, let's first introduce the return value of indexOf, the failure is -1. In the C language, -1 is a "sentinel value, which is given a special meaning, -1 means execution failure, and greater than -1 means success. This convention is followed in JS.

Optimize indexOf judgment

let a = "Hello World"; console.log(~a.indexOf( "lo" ));//-4 <-- true value! console.log(~a.indexOf( "ol" ));//0 <-- false value! Copy code
  • Degree cut

~~ Because it is reversed twice, it is equivalent to the result after executing ToInt32

~~ X is equivalent to truncating the value to a 32-bit integer

Display parsed numeric string

Parsing numeric strings is to allow non-numeric characters in the string, parsing from left to right, and stop if it encounters non-numeric characters. The conversion does not allow non-numeric characters, otherwise it will fail and return NaN.

a = "42" b = "42px" console.log(Number(a), Number(b))//42 NaN console.log(parseInt(a), parseInt(b))//42 42 Copy code

parseInt(..) firstly convert the parameter type to a string and then parse it

parseInt( 0.000008 );//0 ("0" comes from "0.000008") parseInt( 0.0000008 );//8 ("8" comes from "8e-7") parseInt( false, 16 );//250 ("fa" comes from "false") parseInt( parseInt, 16 );//15 ("f" comes from "function..") parseInt( "0x10" );//16 parseInt( "103", 2 );//2 Copy code

Display converted to Boolean

Boolean(X) or !!X

Privacy type conversion

Tips

When an operand is an object, the ToPrimitive operation will be called first, and then [[DefaultValue]] will be called again, using the number as the context. For detailed explanation, see ToPrimitive.

The ToNumber abstract operation deals with objects in a similar way. For example: if the valueOf() operation of the array cannot get a simple basic type value, it will call toString() instead

Implicit coercion between string and number

  • If one of the operands of the operator is a string or a string can be obtained, string concatenation is performed; otherwise, number addition is performed.

Implicit cast Boolean value

  • The conditional judgment expression in the if (..) statement.
  • for (..; ..; ..) The conditional judgment expression in the statement (the second one).
  • Conditional judgment expressions in while (..) and do..while(..) loops.
  • ?: Conditional judgment expression in.
  • The operand on the left side of the logical operator || (logical OR) and && (logical AND) (as a conditional judgment expression).

|| and &&

|| and && are not "logical operators" in the true sense, they are more closely related to "selector operators" or "operand selector operators". Because what they return is not a boolean value, the return value is one of the two operands.

var a = 42; var b = "abc"; var c = null; console.log(a || b, a && b, c || b, c && b)//42,abc,abc,null Copy code

For ||, if the conditional judgment result is true, the value of the first operand (a and c) is returned, and if it is false, the value of the second operand (b) is returned.

&& On the contrary, if the condition is true, it returns the value of the second operand (b), if it is false, it returns the value of the first operand (a and c).

Coercion of symbols

ES6 allows explicit casts from symbols to strings, but implicit casts will cause errors.

Symbols can not be coerced to a number (explicit and implicit will produce errors), but can be coerced to Boolean (explicit and implicit results are true).

=== and ==

Official Detailed Explanation of Equality Judgment

"== allows forced type conversion in equality comparisons, and === does not allow."

performance

=== and == will both check the type of the operand, and if the type of == is different, a type conversion will be performed, and the performance difference in microseconds can be ignored. In fact, when comparing two objects, they work on the same principle; when two objects point to the same value, they are considered equal, and no coercive type conversion occurs.

Equality comparison

  • Numbers and strings

    a = 42 b = "42" console.log(a === b)//false console.log(a == b)//true
    • a==b ?

      ES5

      • a b a == ToNumber(b)
      • a b ToNumber(a) = b
  • b = "42" console.log(b == true)//false

    ES5

    • a Boolean, ToNumber(a) == b
    • b Boolean a == ToNumber(b)
  • null undefined

    == null undefined

    var a = null; var b; a == b;//true a == null;//true b == null;//true a == false;//false b == false;//false a == "";//false b == "";//false a == 0;//false b == 0;//false
  • ES5 == ToPrimitive

a = 42 b = [42] a == b//true c = "obc" d = Object(c) c == d
    • Number.prototype.valueOf = function () { return 3 } console.log(new Number(2) == 3)//true
    • a == 2 && a == 3

      // valueOf let i = 2 Number.prototype.valueOf = function () { return i++ } var a = new Nummber(2) if (a == 2 && a == 3) { //true } // defineProperty let obj = { a: 1 } Object.defineProperty(obj, 'a', { get () { return i++ } })
    • ==

      "0" == null;//false "0" == undefined;//false "0" == false;//true -- "0" == NaN;//false "0" == 0;//true "0" == "";//false false == null;//false false == undefined;//false false == NaN;//false false == 0;//true - dizzy! false == "";//true - dizzy! false == [];//true - dizzy! false == {};//false "" == null;//false "" == undefined;//false "" == NaN;//false "" == 0;//true - dizzy! "" == [];//true - dizzy! "" == {};//false 0 == null;//false 0 == undefined;//false 0 == NaN;//false 0 == [];//true - dizzy! Copy code
    • extreme case

      2 == [2]//true [] == ![]//true "" == [null]//true 0 == "\n"//true Copy code

Abstract relationship comparison

a <= b will be processed as! (b <a) to judge

  • Both sides of the comparison are strings: compare in alphabetical order
  • Others: first call ToPrimivite, if a non-character string appears, it will be compared according to the ToNumber coercion type conversion to a number

syntax

Statements and expressions

A sentence is equivalent to a sentence that can express the meaning completely, and consists of a set of words or N expressions, which are connected by operators. The expression is equivalent to a phrase, and the expression can be composed of smaller expressions, and can have a complete meaning or not.

The result value of the statement

The statement has a result value, which stipulates that the result value of the definition var is

undefined
.

The syntax does not allow us to assign the result of a statement only to another variable, such as:

var a, b a = if (true) { b = 4+38 }//The if code block outputs 42 in the console, but assignment to another variable is not allowed Copy code

But in the actual process, we can get the execution result of the statement in other ways: eval() is strongly not recommended, the do{...} expression in ES7 executes the code block

Expression side effects

The result value of the assignment statement can be combined with the judgment condition

Context rule

  • {...} This leads to a feature of JS that is not very recognized (not recommended), the label statement
    foo: for(let i = 0; i <4; i++) {//foo label for (let j =0; j <4; j++) { if (i == j) { console.log('skipped', i, j) //Jump to the next loop of foo i+1 continue foo } if ((i * j)% 2 == 1) { console.log('Skip odd numbers', i, j) //Skip this cycle, j+1 continue } console.log('not skipped', i, j) } } Copy code
    The greater use of labeled loop jump is: use it with break to jump from the inner layer to the outer layer
    foo: for(let i = 0; i <4; i++) { for (let j =0; j <4; j++) { if ((i * j)% 2 == 1) { console.log('Skip odd numbers', i, j) break foo//Jump out of the loop and code block where label foo is located } console.log('not skipped', i, j) } } Copy code

Tips

[] + {}//"[object Object]" {} + []//0 Copy code

In the first line of code, {} appears in the + operator expression, so it is treated as a value (empty object). Chapter 4 said that [] will be coerced to "", and {} will be coerced to "[object Object]".

But in the second line of code, {} is treated as an independent empty code block (does not perform any operation). There is no need for a semicolon at the end of the code block, so there is no grammatical problem here. Finally + [] will explicitly cast [] (see Chapter 4) to 0.

Trivia

  • In fact, there is no else if in JS, but if and else contain only a single statement, the code block {} can be omitted. In fact, the else if we often use is as follows:
if (a) { } else { if (b) {} else {} } Copy code

Operator precedence

The official explanation of operator precedence

Asynchrony and performance