(46 - Chapter III 20218 + a1043)
grammar
Case sensitive
ECMAScript is case sensitive.
identifier
An identifier is the name of a variable, function, property, or function parameter.
An identifier consists of one or more of the following characters:
- The first character must be a letter, underscore () Or dollar sign ($);
- The remaining characters can be letters, underscores, dollar symbols, or numbers.
Recommendation: when writing identifiers, it is generally recommended to use hump case, that is, the first letter of the first word is lowercase, and the first letter of each subsequent word is uppercase, such as
firstSecond myCar doSomethingImportant
be careful
Keywords, reserved words, Booleans, and null Cannot be used as an identifier.
notes
Single line note://
Multiline comment: / **/
Strict mode
ES5 adds the concept of strict mode.
After the strict mode is enabled, some nonstandard code writing methods will report errors.
Turn on strict mode for the entire script:
Add a sentence to the first line of the script:
"use strict";
You can also turn on strict mode for individual function bodies:
Add a sentence at the beginning of the function:
function doSometing(){ "use strict"; //Function body }
sentence
Semicolon (;) after statement It is suggested to add.
It's okay not to add it. The parser will make it up (slightly consuming performance)
(adding a mark reduces the possibility of error reporting)
In addition, try to use code blocks to put the content more clearly and reduce the possibility of error reporting.
if (test) { test = false; console.log(test); }
// Effective, but easy to lead to errors, which should be avoided if (test) console.log(test); // recommend if (test) { console.log(test); }
Keywords and reserved words
Keywords cannot be used as identifiers or attribute names;
Keywords after ES6 include:
break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this default
if throw delete import try
Reserved words of ES6:
Always keep:
enum
Reserved in strict mode:
implements package public
interface protected static
let private
Reserved in module code:
await
Just avoid the identifier attribute name.
variable
var keyword
If only variables are defined without assignment, the defined variables are undefined.
Variables can be overridden after being defined:
var message="hi"; message=123;//Yes, but not recommended.
Block level scope when var is within a function
var is used to declare variables inside the function, which cannot be accessed outside the function
function test() { var message = "hi"; // local variable } test(); console.log(message); // Error!
But there is a solution that is not worth recommending:
Write the variable name and assign value directly in the function, so that the written variable becomes a global variable and can be accessed externally
function test() { message = "hi"; // global variable } test(); console.log(message); // "hi"
Note that although you can define global variables by omitting the var operator, it is not recommended. Global variables defined in a local scope are difficult to maintain and can cause confusion. This is because we can't judge whether the omission of var is intentional at once. In strict mode, if you assign a value to an undeclared variable like this, it will cause an eferenceError to be thrown
Declaring multiple variables can be separated by commas:
var message = "hi", found = false, age = 29;
Note that variable names should not be defined as eval and arguments.
var declaration promotion
Declaring variables with var will automatically promote to the top of the scope (only the variable name is promoted to the top, but there is no assignment)
function foo() { console.log(age); var age = 26; } foo(); // undefined
The above code is equivalent to:
function foo() { var age; console.log(age); age = 26; } foo(); // undefined
In addition, you can use var to declare the same variable multiple times, which is equivalent to rewriting the variable:
function foo() { var age = 16; var age = 26; var age = 36; console.log(age); } foo(); // 36
let declaration
Let, like var, is also used to declare variables, but let has block level scope. var does not have block level scope, but var has function scope, such as:
if (true) { var name = 'Matt'; console.log(name); // Matt } console.log(name); // Matt if (true) { let age = 26; console.log(age); // 26 } console.log(age); // ReferenceError: age is not defined
Because block level scopes are subsets of function scopes, let s also have function scopes.
let cannot declare repeatedly:
var name; var name; let age; let age; // SyntaxError; The identifier age has been declared
js engine will record the identifier declared by the variable and its scope, so the same identifier can be nested.
var name = 'Nicholas'; console.log(name); // 'Nicholas' if (true) { var name = 'Matt'; console.log(name); // 'Matt' } let age = 30; console.log(age); // 30 if (true) { let age = 26; console.log(age); // 26 }
The redundant declaration and error reporting will not be affected by the mixed use of let and var. These two keywords do not declare different types of variables, they just indicate how variables exist in the relevant scope
var name; let name; // SyntaxError let age; var age; // SyntaxError
Temporary dead zone
Let is different from var. an error will be reported if a variable is referenced before a let declares a variable. (ReferenceError)
Global declaration
let declared variables will not be called attributes of window objects (var declared variables will)
var name = 'Matt'; console.log(window.name); // 'Matt' let age = 26; console.log(window.age); // undefined
The variable of let is not the attribute of window object, but the let declaration still exists in the global scope, and the corresponding variable will continue in the life cycle.
Conditional declaration
Is two script tags on the same page. As long as it is on the same page, you cannot declare the second time with let. Will report an error. But var can be declared repeatedly.
<script> let name = 'Nicholas'; let age = 36; </script> <script> // Suppose the script is not sure whether a variable with the same name has been declared in the page // Then it can assume that it has not been declared if (typeof name === 'undefined') { let name; } // name is restricted to the scope of if {} block // Therefore, this assignment is equivalent to global assignment name = 'Matt'; try { console.log(age); // If age has not been declared, an error will be reported } catch(error) { let age; } // age is restricted to the scope of the catch {} block // Therefore, this assignment is equivalent to global assignment age = 26; </script>
It's a good thing to note that conditional declarations cannot be made with let s, because conditional declarations are an anti pattern that makes programs more difficult to understand. If you find yourself using this model, there must be a better alternative.
let declaration in for loop
If for is an asynchronous logic, such as timer, because var has no block level scope. Therefore, the final value received by each asynchronous task is the maximum value of the counter in the for loop.
Using let does not work because let has a block level scope, which keeps the value received each time different.
for (let i = 0; i < 5; ++i) { setTimeout(() => console.log(i), 0) } // 0, 1, 2, 3, 4 will be output
const statement
const is used in the same way as let.
However, const declares constants, which cannot be modified after declaration.
const can be used with a for of / for in loop.
for (const key in {a: 1, b: 2}) { console.log(key); } // a, b for (const value of [1,2,3,4,5]) { console.log(value); } // 1, 2, 3, 4, 5
Best practice statement and style
Do not use var;
When both let and const can be used, choose const.
data type
ECMAScript's six simple data types (raw data types):
- Undefined
- Null
- Boolean
- Number
- String
- Symbol (new in ES6)
- There are also complex data types Object
typeof operator
Used to detect data types.
"undefined"Indicates that the value is undefined; "boolean"Indicates that the value is Boolean; "string"Indicates that the value is a string; "number"Indicates that the value is a numerical value; "object"Indicates that the value is an object (not a function) or null; "function"Indicates that the value is a function; "symbol"Indicates that the value is a symbol.
let message = "some string"; console.log(typeof message); // "string" console.log(typeof(message)); // "string" console.log(typeof 95); // "number"
(supplement: the return value of typeof displays the returned value type in string. For example:
console.log(typeof true)//Here, take Boolean value as an example, and other values are the same //Return "Boolean" above console.log(typeof typeof true)//Return String
)
Undefined type
The light declaration does not assign a value, and the last variable is undefined;
The variable value is undefined, but it is declared not to assign a value. If you output directly without declaration, an error will be reported;
Note that even if uninitialized variables are automatically assigned undefined values, we still recommend that you declare variables in the
Initialize at the same time. In this way, when typeof returns "undefined", you will know that it is because of the given variable
Quantity has not been declared, not declared but uninitialized.
Test code: it explains the difference between declaring no assignment and not declaring.
let message; // This variable is only declared as defined // age has no declaration if (message) { // This block will not execute } if (!message) { // This block will execute } if (age) { // An error will be reported here }
Null type
Null indicates a null object pointer.
As long as the object has no variable value to save, it can be used to store the variable in the future.
Test code: explains the difference between null and undefined:
let message = null; let age; if (message) { // This block will not execute } if (!message) { // This block will execute } if (age) { // This block will not execute } if (!age) { // This block will execute }
Boolean type
There are two values: true and false;
Be case sensitive.
You can call a specific Boolean() transformation function to convert other values into Boolean values;
Conversion rules of other data types to Boolean values:
data type | Value to true | Value converted to false |
---|---|---|
Boolean | true | false |
String | Non empty string | "" (empty string) |
Number | Non zero value (including infinite value) | 0,NaN |
Object | Any object | null |
Undefined | N/A (not present) | undefined |
Number type
decimal system:
Write integers directly
55
octal number system:
The first octal digit must be zero (0), followed by the octal digit of the response (0 ~ 7)
070 / / valid octal
079 / / invalid
(octal is invalid in strict mode, and an error will be thrown)
hexadecimal:
The prefix 0x (case sensitive) must be preceded by hexadecimal digits (09 and AF). Hexadecimal numbers can be in both case.
0xA / / hex 10
0x1f / / hex 31
Note that due to the way JavaScript saves values, there may be positive zero (+ 0) and negative zero ( 0) in practice. Positive zero and negative zero are considered equal in all cases, which is specially explained here.
Floating point value
Storing floating-point values uses twice as much memory as storing integer values. Therefore, ECMAScript will convert the value to integer as much as possible
Note: there is a bug in the addition of floating-point values. In js, 0.1 + 0.2 ≠ 0.3
Note that this rounding error is due to the use of IEEE 754 values, which is not unique to ECMAScript. Other languages that use the same format also have this problem.
The detected value is within infinity
To determine whether the value is finite, you can use the isfinish() function
let result = Number.MAX_VALUE + Number.MAX_VALUE; console.log(isFinite(result)); // false
NaN
NaN: special value. Means "Not a Number";
The operation for the value to be returned failed (instead of throwing an error)
NaN is not equal to any value, including yourself
To determine whether a value is NaN, you can use the isNaN() function.
isNaN returns true for any value that cannot be converted to a numeric value
console.log(isNaN(NaN)); // true console.log(isNaN(10)); // false, 10 is a numeric value console.log(isNaN("10")); // false, which can be converted to the value 10 console.log(isNaN("blue")); // true, cannot be converted to numeric value console.log(isNaN(true)); // false, which can be converted to the value 1
Note that although not common, isNaN() can be used for test objects. At this point, the valueOf() of the object will be called first
Method, and then determine whether the returned value can be converted to a numeric value. If not, call the toString() method again,
And test its return value. This is usually how ECMAScript built-in functions and operators work, which will be discussed later in this chapter
Numerical conversion rules
There are three functions that can convert non numeric values to numeric values:
Number(), parseInt() and parseFloat();
Number() can be applied to any data type;
parseInt() and parseFloat() are mainly used to convert strings into numeric values;
Number() function conversion rule:
- Boolean value: true is converted to 1 and false to 0
- Value: return directly
- null: return 0
- undefined: returns NaN
- String: apply the following rules:
- If the string contains numeric characters, including those preceded by plus and minus signs, it is converted to a decimal value.
- If the string contains a valid floating-point value, such as "1.1", it is converted to the corresponding floating-point value
- If the string contains a valid hexadecimal format, such as "0xf", it is converted to the corresponding decimal integer
- Returns 0 if it is an empty string
- If the string contains characters other than the above, NaN
- Object: call the ValueOf () method and convert the returned value according to the above rules. If the conversion result is NaN, call the toString () method, and then convert according to the rules of string conversion.
After the parseInt() function gets the value, it will start with the first non empty string. If the first value encountered is not a value or plus or minus sign, it will immediately return NaN. (an empty string will also return NaN);
If the first string parseInt encounters is a numeric character, plus or minus sign, it will continue to detect each character at once until the end of the string, or after encountering a non numeric character. Directly return the detected value.
The second parameter of parseInt() function can specify the hexadecimal number (binary decimal, etc.);
parseFloat () is similar to parseInt (). It can be parsed after the first decimal point and before the second decimal point;
String type
String type, which can be identified by double quotation marks ("), single quotation marks ('), or back quotation marks (`).
Character literal
Literal | meaning |
---|---|
\n | Line feed |
\t | Tabulation |
\b | Backspace |
\r | enter |
\f | Page change |
\\ | Backslash (\) |
\' | Single quotation mark (') |
...... |
The length of the string can be obtained through the length attribute:
let text = "This is the letter sigma: \u03a3."; console.log(text.length); // 28
String characteristics
The string is immutable. Every time the value of a variable string is modified, the original string is destroyed first, and then the new string is stored in the variable.
Convert to string
Almost all values have a toString() method. Use this method to convert strings.
null and undefined values have no toString() method.
If you are not sure whether a value is null or undefined. You can use the String() transformation function:
- If the value has a toString () method, call the method (without passing parameters) and return the result.
- "Null" is returned if the value is null“
- If the value is undefined, "undefined" is returned“
Note that using the plus operator to add an empty string "" to a value can also convert it to a string
Template literal
Added after ES6 is (`), in which line breaks will be retained.
String interpolation
let value = 5; let exponent = 'second'; // Previously, string interpolation was implemented as follows: let interpolatedString = value + ' to the ' + exponent + ' power is ' + (value * value); // Now, you can use template literals to achieve this: let interpolatedTemplateLiteral = `${ value } to the ${ exponent } power is ${ value * value }`; console.log(interpolatedString); // 5 to the second power is 25 console.log(interpolatedTemplateLiteral); // 5 to the second power is 25
All inserted values are forcibly converted to strings using toString(), and any JavaScript expression can be used for insertion
Value. Nested template strings do not need to be escaped:
console.log(`Hello, ${ `World` }!`); // Hello, World! Called when an expression is converted to a string toString(): let foo = { toString: () => 'World' }; console.log(`Hello, ${ foo }!`); // Hello, World! Functions and methods can be called in interpolation expressions: function capitalize(word) { return `${ word[0].toUpperCase() }${ word.slice(1) }`; } console.log(`${ capitalize('hello') }, ${ capitalize('world') }!`); // Hello, World! In addition, templates can also insert their previous values: let value = ''; function append() { value = `${value}abc` console.log(value); } append(); // abc append(); // abcabc append(); // abcabcabc
Template literal label function
Label function is a function that can customize interpolation. The tag function will receive the template separated by the interpolation token and the result of each expression.
let a = 6; let b = 9; function simpleTag(strings, aValExpression, bValExpression, sumExpression) { console.log(strings); console.log(aValExpression); console.log(bValExpression); console.log(sumExpression); return 'foobar'; } let untaggedResult = `${ a } + ${ b } = ${ a + b }`; let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`; // ["", " + ", " = ", ""] // 6 // 9 // 15 console.log(untaggedResult); // "6 + 9 = 15" console.log(taggedResult); // "foobar"
Because the number of expression parameters is variable, the rest operator is usually used to store the collected arguments into the array:
let a = 6; let b = 9; function simpleTag(strings, ...expressions) { console.log(strings); for(const expression of expressions) { console.log(expression); } return 'foobar'; } let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`; // ["", " + ", " = ", ""] // 6 // 9 // 15 console.log(taggedResult); // "foobar"
If you want to splice strings with expressions:
let a = 6; let b = 9; function zipTag(strings, ...expressions) { return strings[0] + expressions.map((e, i) => `${e}${strings[i + 1]}`) .join(''); } let untaggedResult = `${ a } + ${ b } = ${ a + b }`; let taggedResult = zipTag`${ a } + ${ b } = ${ a + b }`; console.log(untaggedResult); // "6 + 9 = 15" console.log(taggedResult); // "6 + 9 = 15"
Original string
// Unicode example // \u00A9 is a copyright symbol console.log(`\u00A9`); // © console.log(String.raw`\u00A9`); // \u00A9 // Line feed example console.log(`first line\nsecond line`); // first line // second line console.log(String.raw`first line\nsecond line`); // "first line\nsecond line" // Not for actual line breaks // They are not converted to the form of escape sequences console.log(`first line second line`); // first line // second line console.log(String.raw`first line second line`); // first line // second line
In addition, you can also use the first parameter of the tag function, that is, the string array The raw property gets the original content of each string
function printRaw(strings) { console.log('Actual characters:'); for (const string of strings) { console.log(string); } console.log('Escaped characters;'); for (const rawString of strings.raw) { console.log(rawString); } } printRaw`\u00A9${ 'and' }\n`; // Actual characters: // © //(line break) // Escaped characters: // \u00A9 // \n
Symbol type
Symbol is a new data type in ES6.
Symbol instances are unique and immutable.
The purpose of Symbol is to ensure that object attributes use unique identifiers and there is no risk of attribute conflict. (make sure the object properties are unique)
Symbol is used to create a unique token, which can be used as an object attribute in non string form.
Basic Usage
Symbols need to be initialized with the symbol() function. Because the symbol itself is the original data type. Therefore, the typeof operator returns symbol for the symbol:
let sym = Symbol(); console.log(typeof sym); // symbol
The Symbol() function can pass in string parameters as the description of the Symbol. The specific function is unclear:
let genericSymbol = Symbol(); let otherGenericSymbol = Symbol(); let fooSymbol = Symbol('foo'); let otherFooSymbol = Symbol('foo'); console.log(genericSymbol == otherGenericSymbol); // false console.log(fooSymbol == otherFooSymbol); // false
As long as the Symbol() instance is created and used as a new attribute of the object, it can be guaranteed that it will not overwrite the existing object attributes, whether symbol attributes or string attributes
let genericSymbol = Symbol(); console.log(genericSymbol); // Symbol() let fooSymbol = Symbol('foo'); console.log(fooSymbol); // Symbol(foo);
Most importantly, the Symbol () function cannot be used as a constructor with the new keyword. This is done to avoid creating Symbol wrapper objects:
let myBoolean = new Boolean(); console.log(typeof myBoolean); // "object" let myString = new String(); console.log(typeof myString); // "object" let myNumber = new Number(); console.log(typeof myNumber); // "object" let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor
To wrap objects with symbols, you can borrow the Object() function:
let mySymbol = Symbol(); let myWrappedSymbol = Object(mySymbol); console.log(typeof myWrappedSymbol); // "object"
Use global symbol registry
Symbol. The for () method performs idempotent operations on each string key. When a string is called for the first time, it will check the global runtime registry and find that there is no corresponding symbol, so a new symbol instance will be generated and added to the registry. Subsequent calls using the same string will also check the registry, find the symbol corresponding to the string, and then return the symbol instance.
let fooGlobalSymbol = Symbol.for('foo'); // Create a new symbol let otherFooGlobalSymbol = Symbol.for('foo'); // Reuse existing symbols console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
Even with the same Symbol description, the symbols defined in the global registry are not the same as those defined using Symbol():
let localSymbol = Symbol('foo'); let globalSymbol = Symbol.for('foo'); console.log(localSymbol === globalSymbol); // false
Symbols in the global registry must be created using string keys, so they are passed to symbol as parameters Any value of for () is converted to a string. In addition, the keys used in the registry are also used as symbolic descriptions.
let emptyGlobalSymbol = Symbol.for(); console.log(emptyGlobalSymbol); // Symbol(undefined)
Symbol. The keyfor() function is used to query the global registry. This method receives symbols and returns the string key corresponding to the global symbols. If the global symbol is not queried, undefined is returned.
String key. If the query is not a global symbol, return undefined. // Create global symbol let s = Symbol.for('foo'); console.log(Symbol.keyFor(s)); // foo // Create common symbols let s2 = Symbol('bar'); console.log(Symbol.keyFor(s2)); // undefined If passed to Symbol.keyFor()Is not a symbol, the method throws TypeError: Symbol.keyFor(123); // TypeError: 123 is not a symbol
Use Symbol symbol as attribute
Symbols can be used wherever strings or numeric values can be used as attributes. This includes the object literal attribute and object defineProperty()/Object. Defineproperties() defines the properties of the. Object literals can only use symbols as attributes in calculated attribute syntax.
let s1 = Symbol('foo'), s2 = Symbol('bar'), s3 = Symbol('baz'), s4 = Symbol('qux'); let o = { [s1]: 'foo val' }; // You can also: o [S1] ='foo Val '; console.log(o); // {Symbol(foo): foo val} Object.defineProperty(o, s2, {value: 'bar val'}); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val} Object.defineProperties(o, { [s3]: {value: 'baz val'}, [s4]: {value: 'qux val'} }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val, // Symbol(baz): baz val, Symbol(qux): qux val}
Similar to object Getownpropertynames() returns the general property array of the object instance, object Getownpropertysymbols() returns an array of symbolic properties of an object instance. The return values of these two methods are mutually exclusive. Object.getOwnPropertyDescriptors() returns an object that contains both regular and symbolic property descriptors. Reflect.ownKeys() returns two types
Key:
let s1 = Symbol('foo'), s2 = Symbol('bar'); let o = { [s1]: 'foo val', [s2]: 'bar val', baz: 'baz val', qux: 'qux val' }; console.log(Object.getOwnPropertySymbols(o)); // [Symbol(foo), Symbol(bar)] console.log(Object.getOwnPropertyNames(o)); // ["baz", "qux"] console.log(Object.getOwnPropertyDescriptors(o)); // {baz: {...}, qux: {...}, Symbol(foo): {...}, Symbol(bar): {...}} console.log(Reflect.ownKeys(o)); // ["baz", "qux", Symbol(foo), Symbol(bar)]
Because a symbol attribute is a reference to a symbol in memory, symbols created directly and used as attributes are not lost. But if
Without explicitly saving references to these attributes, you must traverse all symbolic attributes of the object to find the corresponding attribute key:
let o = { [Symbol('foo')]: 'foo val', [Symbol('bar')]: 'bar val' }; console.log(o); // {Symbol(foo): "foo val", Symbol(bar): "bar val"} let barSymbol = Object.getOwnPropertySymbols(o) .find((symbol) => symbol.toString().match(/bar/)); console.log(barSymbol); // Symbol(bar)
Common built-in symbols
One of the most important uses of these built-in symbols is to redefine them to change the behavior of the native structure. For example, we know that the for of loop uses Symbol on related objects The iterator attribute, then you can redefine the Symbol on the custom object The value of iterator to change the behavior of for when iterating the object. There is nothing special about these built-in symbols. They are the ordinary string properties of the global function Symbol, pointing to an instance of a Symbol. All built-in Symbol attributes are non writable, non enumerable and non configurable.
Note that it is mentioned in ECMAScript When specifying, the name of the symbol in the specification is often referenced with the prefix@@. For example, @@iterator It means Symbol.iterator.
Symbol.asyncIterator
This symbol represents as an attribute "a method that returns the object's default AsyncIterator. Used by the for await of statement".
The for await of loop uses this function to perform asynchronous iterative operations. When looping, they call symbol asyncIterator
Is the key and expects this function to return an object that implements the iterator API. Many times, the returned object is to implement the API
AsyncGenerator for:
class Foo { async *[Symbol.asyncIterator]() {} } let f = new Foo(); console.log(f[Symbol.asyncIterator]()); // AsyncGenerator {<suspended>}
Technically, this is by symbol The objects generated by the asyncinterator function should successively return Promise instances through its next() method. It can be returned by explicitly calling the next() method or implicitly through the asynchronous generator function:
class Emitter { constructor(max) { this.max = max; this.asyncIdx = 0; } async *[Symbol.asyncIterator]() { while(this.asyncIdx < this.max) { yield new Promise((resolve) => resolve(this.asyncIdx++)); } } } async function asyncCount() { let emitter = new Emitter(5); for await(const x of emitter) { console.log(x); } } asyncCount(); // 0 // 1 // 2 // 3 // 4
be careful Symbol.asyncIterator yes ES2018 The specification defines, so there are only very new versions of browsers Support it. About asynchronous iteration and for-await-of See Appendix for details of the cycle A.
Symbol.hasInstance
As an attribute, this symbol represents "a method that determines whether a constructor object recognizes an object as its instance. It is used by the instanceof operator". The instanceof operator can be used to determine whether there is a prototype on the prototype chain of an object instance. The typical usage scenarios of instanceof are as follows:
function Foo() {} let f = new Foo(); console.log(f instanceof Foo); // true class Bar {} let b = new Bar(); console.log(b instanceof Bar); // true
In ES6, the instanceof operator uses symbol Hasinstance function to determine the relationship. With symbol The function with hasinstance as the key will perform the same operation, but the operands are swapped:
function Foo() {} let f = new Foo(); console.log(Foo[Symbol.hasInstance](f)); // true class Bar {} let b = new Bar(); console.log(Bar[Symbol.hasInstance](b)); // true
Symbol.isConcatSpreadable
As an attribute, this symbol represents "a Boolean value. If it is true, it means that the object should level its array elements with Array.prototype.concat()". Array in ES6 prototype. The concat () method will choose how to splice a class array object into an array instance according to the received object type. Overwrite symbol isConcatSpreadable
The value of can modify this behavior.
Array objects will be flattened to the existing array by default. False or false values will cause the whole object to be appended to the end of the array. class
Array objects will be appended to the end of the array by default. True or true value will cause this class of array objects to be flattened to the array instance. his
It is not an object of class array object in symbol Isconcatspreadable is ignored when it is set to true.
let initial = ['foo']; let array = ['bar']; console.log(array[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(array)); // ['foo', 'bar'] array[Symbol.isConcatSpreadable] = false; console.log(initial.concat(array)); // ['foo', Array(1)] let arrayLikeObject = { length: 1, 0: 'baz' }; console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(arrayLikeObject)); // ['foo', {...}] arrayLikeObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz'] let otherObject = new Set().add('qux'); console.log(otherObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(otherObject)); // ['foo', Set(1)] otherObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(otherObject)); // ['foo']
Symbol.iterator
This symbol, as an attribute, represents "a method that returns the object's default iterator. Used by the for of statement".
Symbol.match
This symbol, as an attribute, represents "a regular expression method that uses a regular expression to match a string. It is used by the String.prototype.match() method". String. prototype. The match () method uses symbol Match is a function of the key to evaluate the regular expression. This function is defined by default on the prototype of regular expression, so all regular expression instances are valid parameters of this string method by default:
console.log(RegExp.prototype[Symbol.match]); // ƒ [Symbol.match]() { [native code] } console.log('foobar'.match(/bar/)); // ["bar", index: 3, input: "foobar", groups: undefined]
Passing in a non regular expression value to this method causes the value to be converted to a RegExp object. If you want to change this behavior and let the method use parameters directly, you can redefine symbol The match function replaces the default behavior of evaluating regular expressions, allowing the match() method to use non regular expression instances. Symbol. The match function receives a parameter, which is the string instance that calls the match() method. There is no limit to the value returned:
class FooMatcher { static [Symbol.match](target) { return target.includes('foo'); } } console.log('foobar'.match(FooMatcher)); // true console.log('barbaz'.match(FooMatcher)); // false class StringMatcher { constructor(str) { this.str = str; } [Symbol.match](target) { return target.includes(this.str); } } console.log('foobar'.match(new StringMatcher('foo'))); // true console.log('barbaz'.match(new StringMatcher('qux'))); // false
Symbol.replace
This symbol represents as an attribute "a regular expression method that replaces a matching substring in a string. Used by the String.prototype.replace() method". String. prototype. The replace () method uses symbol Replace is a function of the key to evaluate the regular expression. This function is defined by default on the prototype of regular expression, so all regular expression instances are valid parameters of this string method by default:
console.log(RegExp.prototype[Symbol.replace]); // ƒ [Symbol.replace]() { [native code] } console.log('foobarbaz'.replace(/bar/, 'qux')); // 'fooquxbaz'
Passing in a non regular expression value to this method causes the value to be converted to a RegExp object. If you want to change this behavior, let the method
Using parameters directly, you can redefine symbol Replace function to replace the default behavior of evaluating regular expressions, so that
The replace () method uses a non regular expression instance. Symbol. The replace function takes two parameters, the caller of replace()
String instance and replacement string of method. There is no limit to the value returned:
class FooReplacer { static [Symbol.replace](target, replacement) { return target.split('foo').join(replacement); } } console.log('barfoobaz'.replace(FooReplacer, 'qux')); // "barquxbaz" class StringReplacer { constructor(str) { this.str = str; } [Symbol.replace](target, replacement) { return target.split(this.str).join(replacement); } } console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux')); // "barquxbaz
Symbol.search
"A regular expression method that returns the index in a string that matches the regular expression. Used by the String.prototype.search() method"
Symbol.species
A function value that acts as a constructor for creating derived objects
Symbol.split
A regular expression method that splits a string at the index that matches the regular expression. By string prototype. The split () method uses
Symbol.toPrimitive
"A method that converts an object to the corresponding original value. Used by the ToPrimitive abstract operation"
Symbol.toStringTag
"A string used to create the default string description of the object. Used by the built-in method Object.prototype.toString()
Symbol.unscopables
All and inherited properties of an object will be excluded from the with environment binding of the associated object
Not recommended with,Therefore, it is not recommended Symbol.unscopables.
(note! Because there are many methods of symbols, careful reading will go against my original intention of laziness, so I cut down the details. Mainly because of my technical dishes, I can't summarize symbols)
Object type
An object is a collection of data and functions.
Create an object using the new operator:
let o=new Object()
Each Object has the following properties and methods:
- constructor: the function used to create the current object.
- hasOwnProperty (propertyName): used to judge whether a given property exists on the current object instance (not the prototype). To check, the property name must be a string (such as o.hasOwnProperty("name")) or a symbol.
- isPrototypeOf (object): used to judge whether the current object is the prototype of another object.
- propertyIsEnumerable (propertyName): used to judge whether a given property can be enumerated with a for in statement. Like hasOwnProperty(), the property name must be a string.
- toLocaleString(): returns the string representation of the object, which reflects the localized execution environment of the object.
- toString(): returns the string representation of the object.
- valueOf(): returns the string, numeric value or Boolean representation corresponding to the object. It is usually the same as the return value of toString().
Because Object in ECMAScript is the base class of all objects, any Object has these properties and methods.
Note that strictly speaking, ECMA-262 The behavior of the object in is not necessarily appropriate JavaScript Other objects in. For example, in the browser environment BOM and DOM Objects are host objects defined and provided by the host environment. The host object is not affected ECMA-262 Constraints, so they may or may not inherit Object.
(81 - Operator 20220 + b0209)
unary operator
Increment / decrement operator
Prefix increment / decrement will add / subtract 1 to the value:
let age=10; ++age;
let age=29; --age;
The prefix increment / decrement changes before the statement is evaluated.
Prefix increment / decrement has equal priority in the statement, so it will be evaluated from left to right.
The increment and decrement of the suffix version occur only after the statement is evaluated.
let age=10; age++;
let age=29; age--;
These four operators can work on any value, meaning that they are not limited to integers -- strings, Booleans, floating-point values, and even objects. The increment and decrement operators follow the following rules:
- For a string, if it is a valid numeric form, it is converted to a numeric value and the change is applied. Variable types are numeric values programmed from strings.
- For a string, if it is not a valid numeric form, set the value of the variable to NaN. Variable type changes from string to numeric.
- For Boolean values, if false, convert to 0 and apply the change. The variable type changes from Boolean to numeric.
- For Boolean values, if true, convert to 1 and apply the change. The variable type changes from Boolean to numeric.
- For floating-point values, add 1 or subtract 1
- If it is an object, call its valueOf () method to get the operable value. Apply the above rules to the resulting values. In the case of NaN, toString() is called and other rules are applied again. Variable type changes from object to value.
let s1 = "2"; let s2 = "z"; let b = false; let f = 1.1; let o = { valueOf() { return -1; } }; s1++; // The value becomes the value 3 s2++; // The value becomes NaN b++; // The value becomes the value 1 f--; // The value becomes 0.100000000000000000 9 (because the floating-point number is imprecise) o--; // The value becomes - 2
Unary addition and subtraction
Putting the plus sign in front of the variable is equivalent to executing Number (), which will turn the variable into Number type:
let s1 = "01"; let s2 = "1.1"; let s3 = "z"; let b = false; let f = 1.1; let o = { valueOf() { return -1; } }; s1 = +s1; // The value becomes the value 1 s2 = +s2; // The value becomes the value 1.1 s3 = +s3; // The value becomes NaN b = +b; // The value becomes a value of 0 f = +f; // Unchanged, or 1.1 o = +o; // The value becomes a value of - 1
Putting the minus sign in front of the variable will also perform data conversion first, and then reverse the data converted to Number:
let s1 = "01"; let s2 = "1.1"; let s3 = "z"; let b = false; let f = 1.1; let o = { valueOf() { return -1; } }; s1 = -s1; // The value becomes a value of - 1 s2 = -s2; // The value becomes a value of -1.1 s3 = -s3; // The value becomes NaN b = -b; // The value becomes a value of 0 f = -f; // Become -1.1 o = -o; // The value becomes the value 1
Bitwise operators
Bitwise non
Tilde (~)
let num1 = 25; // Binary 000000000 11001 let num2 = ~num1; // Binary 11111111111111111111111111100110 console.log(num2); // -26
Bitwise AND
and (&)
let num1 = 25; // Binary 000000000 11001 let num2 = ~num1; // Binary 11111111111111111111111111100110 console.log(num2); // -26
Bitwise OR
Pipe symbol (|)
let result = 25 | 3; console.log(result); // 27
Bitwise XOR
Caret (^)
let result = 25 ^ 3; console.log(result); // 26
Shift left
Two less than signs (< <)
let oldValue = 2; // Equal to binary 10 let newValue = oldValue << 5; // Equal to binary 1000000, i.e. decimal 64
Signed right shift
Two greater than signs (> >)
let oldValue = 64; // Equal to binary 1000000 let newValue = oldValue >> 5; // Equal to binary 10, i.e. decimal 2
unsigned right shift
3 greater than signs (> > >)
let oldValue = 64; // Equal to binary 1000000 let newValue = oldValue >>> 5; // Equal to binary 10, i.e. decimal 2
Boolean operator
There are three Boolean operators: logical not, logical and, logical or.
Logical non
The logical non operator is an exclamation mark (!)
Its function is to invert variables after they are converted to Boolean values. There are the following rules:
-
Returns false if the operand is an object.
-
Returns true if the operand is an empty string.
-
Returns false if the operand is a non empty string.
-
Returns true if the operand is a numeric value of 0.
-
Returns false if the operand is a non-zero value, including Infinity.
-
Returns true if the operand is null.
-
Returns true if the operand is NaN.
-
Returns true if the operand is undefined.
console.log(!false); // true console.log(!"blue"); // false console.log(!0); // true console.log(!NaN); // true console.log(!""); // true console.log(!12345); // false
Logic and
The logic and operator is composed of two and symbols (& &), which follow the following rules:
- If the first operand is an object, the second operand is returned
- If the second operand is an object, only one operand evaluates to true to return the object.
- If both objects are operands, the second operand is returned.
- If one operand is null, null is returned.
- If one operand is NaN, NaN is returned.
- If one operand is undefined, undefined is returned.
The logical and operator is a short circuit operator: if the first one is false, it will not be read later. If the first one is true, the second one will be viewed. If both are true, the second one will be returned.
(if both conditions are true, it is true. If one condition is false, the result is false)
Logical or
Logic or consists of two pipeline symbols (|), and logic or follows the following rules:
- If the first operand is an object, the first operand is returned.
- If the first operand evaluates to false, the second operand is returned.
- If both numbers are objects, the first operand is returned.
- Returns NULL if both operands are null.
- If both operands are NaN, NaN is returned.
- If both operands are undefined, undefined is returned.
Short circuit characteristic with logic: when the first one is true, the second one will not be read.
(if one is true, it will be true. All false is false)
Multiplicative operator
Multiplication operator
Multiplication operator (*)
The basic characteristics are consistent with the multiplication in junior middle school:
- When JS cannot represent the product, infinity or - Infinity will be returned.
- If any operand is NaN, NaN is returned.
- If Infinity is multiplied by 0, NaN is returned
- If there is an operator that is not a numeric value, it will be converted to a numeric value with Number() before calculation.
Division operator
The division operator is represented by a slash (/), and the division follows the rules:
- If JS cannot represent the result, Infinity or - Infinity is returned.
- If any operator is NaN, NaN is returned
- If Infinity is divided by Infinity, NaN is returned
- If 0 is divided by 0, NaN is returned
- If divided by 0, Infinity or - Infinity is returned
- Infinity divided by any number is infinity
- If there are non numeric, run Number() first and then divide.
Modulo operator
The modulo (remainder) operator is represented by a percentage sign (%), and the modulo operator follows the rules:
- Operators are numeric values. Divide and return the remainder.
- If the dividend is infinite, NaN is returned
- If the divisor is a finite value and the divisor is an infinite value, the divisor is returned.
- If the divisor is 0, the divisor is not 0 and returns 0
- If it is not a numeric value, the Number() conversion is performed before the operation.
Exponential operator
Exponential operator = math Pow () is the same as the exponential operator (* *)
console.log(Math.pow(3, 2); // 9 console.log(3 ** 2); // 9 console.log(Math.pow(16, 0.5); // 4 console.log(16** 0.5); // 4
You can also write:
let sqrt = 16; sqrt **= 0.5; console.log(sqrt); // 4
Additive operator
Addition Operator
The addition operator (+) is used to sum two numbers
If both operands are numeric, the addition operator performs the addition operation and returns the result according to the following rules:
- If any operand is NaN, NaN is returned;
- If Infinity plus Infinity, Infinity is returned;
- If it is - Infinity plus - infinity, then - infinity is returned;
- If Infinity plus Infinity, NaN is returned;
- If + 0 Plus + 0, return + 0;
- If - 0 Plus + 0, return + 0;
- If it is - 0 plus - 0, - 0 is returned.
However, if one of the operands is a string, the following rules apply:
- If both operands are strings, splice the second string after the first string;
- If only one operand is a string, convert the other operand to a string and splice the two strings together.
let result1 = 5 + 5; // Two values console.log(result1); // 10 let result2 = 5 + "5"; // A numeric value and a string console.log(result2); // "55"
subtraction operator
The subtraction operator (-) is also a frequently used operator. Like the addition operator, the subtraction operator also has a set of rules to handle the conversion between different types in ECMAScript:
- If both operands are numeric, perform a mathematical subtraction and return the result.
- If any operand is NaN, NaN is returned.
- If Infinity minus Infinity, NaN is returned.
- If - Infinity minus - infinity, NaN is returned.
- If Infinity minus Infinity, Infinity is returned.
- If it is - Infinity minus infinity, - infinity is returned.
- If + 0 minus + 0, return + 0.
- If + 0 minus - 0, - 0 is returned.
- If - 0 minus - 0, return + 0.
- If any operand is a string, Boolean, null or undefined, use Number() in the background to convert it to a numeric value, and then perform the mathematical operation according to the previous rules. If the conversion result is NaN, the result of subtraction calculation is NaN.
- If any operand is an object, call its valueOf() method to get the value representing it. If the value is NaN, the result of subtraction calculation is NaN. If the object does not have a valueOf() method, call its toString() method, and then convert the resulting string to a numeric value.
let result1 = 5 - true; // true is converted to 1, so the result is 4 let result2 = NaN - 1; // NaN let result3 = 5 - 3; // 2 let result4 = 5 - ""; // '' was converted to 0, so the result is 5 let result5 = 5 - "2"; // "2" is converted to 2, so the result is 3 let result6 = 5 - null; // null is converted to 0, so the result is 5
Relational operator
The usage is the same as that in math class. The result returns a Boolean value. Like other operators in ECMAScript, type conversion and other behaviors will occur when they are applied to different data types:
- If the operands are numeric, a numeric comparison is performed.
- If the operands are all strings, compare the encoding of the corresponding characters in the string one by one.
- If any operand is a numeric value, convert the other operand to a numeric value and perform a numeric comparison.
- If any operand is an object, call its valueOf() method, obtain the result, and then perform the comparison according to the previous rules. If there is no valueOf() operator, call the toString() method to get the result, and then perform the comparison according to the previous rules.
- If any operand is Boolean, convert it to a numeric value and perform the comparison
When comparing strings, the encoding of the corresponding characters in the string will be compared;
When comparing two numbers in string form, we also compare their character codes.
If one is a numerical value, it will be compared according to the numerical value.
(95) equality operator 20221 + b0112
Equal to and not equal to
The operators equal to (= =) and not equal to (! =) in ECMAScript will be cast during operation:
When converting the types of operands, the equality and inequality operators follow the following rules.
- If the operand has a Boolean value, it is converted to a Number for comparison. false is converted to 0, and true is converted to 0
Is 1. - When a string is compared with a number, it attempts to convert the string to a number and then compare it.
- If one operand is an object and the other operand is not, call the valueOf() method of the object to obtain its original value, and then
Compare according to the previous rules.
When comparing, the two operators will follow the following rules.
- null and undefined are equal.
- null and undefined cannot be converted to other types of values for comparison.
- If any operand is NaN, the equality operator returns false and the inequality operator returns true. Remember: even two
Both operands are NaN, and the equality operator also returns false, because NaN is not equal to NaN according to the rule. - If they are both the same operand. If both operands point to the same object,
The equality operator returns true. Otherwise, the two are not equal.
Congruent and incomplete
Congruent (=) and incomplete (!) false is converted to 0 and true to 1.
Note that since the equal and unequal operators have type conversion problems, the use of congruent and incomplete operators is recommended.
This helps maintain the integrity of data types in your code.
Conditional Operator
variable = boolean_expression ? true_value : false_value;
The above code performs the conditional assignment operation, that is, Boolean according to the conditional expression_ The value of expression determines which value to assign to variable. If Boolean_ If expression is true, the value is true_value ; If Boolean_ If expression is false, the value is false_value.
(if the previous expression is true, the first one will be returned; if false, the second one will be returned.)
Assignment operator
Simple assignment is represented by an equal sign (=), and the value on the right hand side is assigned to the variable on the left hand side;
Compound assignments are represented by multiplicative, additive, or bitwise operators followed by an equal sign (=).
- Assignment after multiplication (* =)
- Assignment after division (/ =)
- Assignment after module taking (% =)
- Assignment after addition (+ =)
- Assignment after subtraction (- =)
- Assignment after left shift (< < =)
- Assignment after shift right (> > =)
- Assignment after unsigned right shift (> > =)
These operators are just shorthand syntax, and using them will not improve performance.
comma operator
The comma operator can be used to perform multiple operations in a statement;
You can use the comma operator to assist in assignment. When assigning values, use the comma operator to separate the values, and finally return the last value in the expression:
let num = (5, 1, 4, 8, 0); // The value of num is 0
sentence
if statement
if(Expression 1){ Code block 1 }else if(Expression 2){ Code block 2 }else{ Code block 3 }
(when reading if:
- First, read "expression 1":
- If true, it will enter "code block 1", then execute the logic in "code block 1", and then ignore other code blocks of if.
- If false, expression 2 is read:
- If true, it will go to "code block 2" and ignore the remaining code blocks.
- If false, it will enter "code block 3"
do-while Statements
do { Code block } while (expression); Here is an example: let i = 0; do { i += 2; } while (i < 10);
The do while statement will execute the previous code block once, and then judge the expression.
while statement
while(expression) { Code block}
The while statement will execute the expression first. If the expression is true, it will enter the code block for execution.
for statement
for (initialization; expression; post-loop-expression){statement}
for (let i = 0; i < count; i++) { console.log(i); }
for(Expression 1: define counter;Expression 2: set a limit for the loop; Expression 3: make the counter change){ Executive body}
The for loop first executes expression 1 and then expression 2:
- If expression 2 meets the conditions, it will enter the execution body, and after the execution of the execution body, it will enter expression 3;
- After executing expression 3, it will continue to execute expression 1, and then execute expression 2
- If expression 2 is not satisfied, it will jump out of the loop directly.
Note: the expressions of the for loop are not required, so they can be omitted.
for (;;) { // infinite loop doSomething(); }
For in statement
For in statement is a strict iterative statement, which is used to enumerate the non symbolic key attributes in the object;
for (property in expression) statement
for (const propName in window) { document.write(propName); }
be careful:
- For in can iterate over the attributes in all objects
- If the variable to be iterated by the for in loop is null or undefined, the loop body will not be executed.
For of statement
The for of statement is a strict iterative statement used to traverse the elements of an iteratable object
(elements of iteratable objects: first of all, they are required to be iteratable, so the objects to be traversed are iteratable: such as arrays, objects with iterators, etc.)
Note: if the variable trying to iterate does not support iteration, the for of statement will throw an error.
Label statement
label: statement
example: start: for (let i = 0; i < count; i++) { console.log(i); }
A typical application scenario for label statements is nested loops
break and continue
Using break will immediately exit the loop body and then execute the statement code below the loop.
Using continue will immediately exit the current loop, and then execute the next loop until the expression is not satisfied and exit the loop body.
break and continue can be executed in conjunction with label statements.
break:
let num = 0; outermost: for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { if (i == 5 && j == 5) { break outermost; } num++; console.log(`j=${j}`) } console.log(`iiiiiiiiiiii=${i}`) } console.log(num); // 55
continue:
let num = 0; outermost: for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { if (i == 5 && j == 5) { continue outermost; } num++; console.log(`j=${j}`) } console.log(`iiiiiiiiiiii=${i}`) } console.log(num); // 95
The break case indicates that when the if determines that it is satisfied, break exits directly to the loop body with the tag.
The continue case indicates that when the if judgment is satisfied, continue directly exits the current loop (because the label statement will fall back to the loop marked by the label statement) and starts the next loop.
The combination of tag statement, break and continue can realize complex logic, but it is also easy to make mistakes. Note that labels should use highly descriptive text and should not be nested too deeply.
with statement
The purpose of the with statement is to set the scope of the code to a specific object
with (expression) statement;
let qs = location.search.substring(1); let hostName = location.hostname; let url = location.href; Every line of code above is used location Object. If used with Statement, you can write less code: with(location) { let qs = search.substring(1); let hostName = hostname; let url = href; }
The with statement is not allowed in strict mode, otherwise an error will be thrown.
Warning because the with statement affects performance and is difficult to debug the code, it is generally not recommended to use with in product code
sentence
switch Statements
switch (expression) { case value1: statement break; case value2: statement break; case value3: statement break; case value4: statement break; default: statement }
switch (i) { case 25: console.log("25"); break; case 35: console.log("35"); break; case 45: console.log("45"); break; default: console.log("Other"); }
In the switch statement, in order to avoid unnecessary judgment, it is best to add a break after each statement. If multiple judgments are really needed, it is recommended to add comments.
In js, the switch expression can be constant or variable, and can be any data type!
Note that the switch statement uses the congruent operator when comparing the values of each condition, so it does not cast the data class
Type (for example, the string "10" is not equal to the value 10).
function
function functionName(arg0, arg1,...,argN) { statements }
Use parenthesized form after function call:
function sayHi(name, message) { console.log("Hello " + name + ", " + message); } sayHi("Nicholas", "how are you today?");
Return statement: if the code in the function is executed after return, it will directly jump out of the function body (the code after return will not be executed)
The function can also return no return value. If it does not return, the function will return undefined.
Note that the best practice is that functions either return a value or do not return a value. Functions that return values only under certain conditions can be troublesome, especially when debugging.
Strict mode also has some restrictions on functions:
- Function cannot take eval or arguments as the name;
- The parameter of a function cannot be eval or arguments;
- Two named parameters cannot have the same name.
If the above rules are violated, it will lead to syntax errors and the code will not be executed.
Summary
- The basic data types in ECMAScript include Undefined, Null, Boolean, Number, String and Symbol.
- ECMAScript does not distinguish between integer and floating-point values. There is only one numerical data type, Number.
- Object is a complex data type. It is the base class of all objects in this language. (all things are objects)
- Strict mode imposes restrictions on some error prone parts of the language (errors will be reported if the language is not standardized).
- ECMAScript provides many basic operators, including mathematical operators, Boolean operators, relational operators, equality operators and assignment operators.
- The functions in ECMAScript are different from those in other languages, and other branch statements learn from other languages.
- There is no need to specify the return value of the function, because any function can return any value at any time.
- Functions that do not specify a return value actually return the special value undefined.