当前位置:网站首页>7.9-7.17 new features and grammar of learning plan ES6
7.9-7.17 new features and grammar of learning plan ES6
2022-07-29 09:37:00 【m0_ forty-nine million four hundred and seventy-one thousand si】
1. be familiar with ES6 New features and syntax (2022-7-17)
(1) let、const、block Scope
(2) Object lexical extension 、 Structure of objects and arrays
(3) Extension of string operation method
(4) promise、async、await
(5) modular
(6) Set、WeakSet、WeakMap、Map
One 、 let、const、block Scope
1.let command
Basic usage
ES6 Added let
command , Used to declare variables . Its usage is similar to var
, But the declared variable , Only in let
The command is valid in the code block .
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
The above code is in the code block , Use them separately let
and var
Two variables declared . Then call these two variables outside the code block , result let
Declared variable error ,var
The declared variable returned the correct value . This shows that ,let
Declared variables are only valid in the code block in which they reside .
for
Cycle counter , It is suitable for use let
command .
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
In the above code , Counter i
Only in for
Circulating efficiency , It will report an error if it is quoted outside the circulation .
The following code if used var
, The final output is 10
.
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
In the above code , Variable i
yes var
command-declared , It works globally , So there's only one variable in the whole world i
. Every cycle , Variable i
The value of will change , The loop is assigned to the array a
Inside the delta function console.log(i)
, Inside i
It points to the overall situation i
. in other words , All of the array a
Of the members of i
, It's all pointing to the same i
, What causes the runtime to output is the last round of i
Value , That is to say 10.
If you use let
, Declared variables are only valid in block level scope , The final output is 6.
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
In the above code , Variable i
yes let
Declarative , Current i
Only valid in this cycle , So every cycle of i
It's actually a new variable , So the final output is 6
. You may ask , If the variables for each cycle i
It's all restated , Then how does it know the value of the last cycle , So we can calculate the value of this cycle ? This is because JavaScript The value of the last cycle will be remembered inside the engine , Initialize variables of this round i
when , On the basis of the last round of calculation .
in addition ,for
There's another thing about the cycle , The part that sets the loop variable is a parent scope , Inside the circulatory body is a separate sub scope .
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
The above code runs correctly , Output 3 Time abc
. This means that the variables inside the function i
And loop variables i
Not in the same scope , Each has its own scope ( The same scope cannot be used let
Repeatedly declare the same variable ).
No variable promotion
var
The command will happen “ Variable Promotion ” The phenomenon , That is, variables can be used before they are declared , The value is undefined
. This phenomenon is more or less strange , According to the general logic , Variables should be declared before they can be used .
In order to correct this phenomenon ,let
Command changes the grammatical behavior , The variables it declares must be used after declaration , Otherwise, the report will be wrong .
// var The situation of
console.log(foo); // Output undefined
var foo = 2;
// let The situation of
console.log(bar); // Report errors ReferenceError
let bar = 2;
In the above code , Variable foo
use var
A statement of order , Variable promotion will occur , When the script starts to run , Variable foo
It already exists , But it's not worth it , So it will output undefined
. Variable bar
use let
A statement of order , No variable Promotion . This means that before declaring it , Variable bar
It doesn't exist , If you use it , Will throw a mistake .
Temporary dead zone
As long as there is... In the block level scope let
command , The variables it declares are “ binding ”(binding) This area , No longer affected by the outside .
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
In the above code , There are global variables tmp
, But in block level scope let
A local variable is declared tmp
, Causes the latter to bind the block level scope , So in let
Before declaring variables , Yes tmp
The assignment will report an error .
ES6 Make it clear , If a block exists let
and const
command , Variables declared by this block for these commands , Closed scopes have been formed from the beginning . Always use these variables before declaring them , You're going to report a mistake .
All in all , In code block , Use let
Before a command declares a variable , This variable is not available . This is in grammar , be called “ Temporary dead zone ”(temporal dead zone, abbreviation TDZ).
if (true) {
// TDZ Start
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ end
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
In the above code , stay let
Command declaration variable tmp
Before , All variables tmp
Of “ dead zone ”.
“ Temporary dead zone ” Also means that typeof
It's no longer a 100% safe operation .
typeof x; // ReferenceError
let x;
In the above code , Variable x
Use let
A statement of order , So before the announcement , All belong to x
Of “ dead zone ”, As long as this variable is used, an error will be reported . therefore ,typeof
The runtime will throw a ReferenceError
.
As a comparison , If a variable is not declared at all , Use typeof
Instead of reporting a mistake .
typeof undeclared_variable // "undefined"
In the above code ,undeclared_variable
Is a non-existent variable name , The result returned to “undefined”. therefore , In the absence of let
Before ,typeof
Operators are 100% safe , Never report a mistake . Now that doesn't hold . This design is to let everyone develop good programming habits , Variables must be used after declaration , Otherwise, it will be wrong .
There are some “ dead zone ” It's more hidden , It's not easy to find .
function bar(x = y, y = 2) {
return [x, y];
}
bar(); // Report errors
In the above code , call bar
The reason the function reported an error ( Some implementations may not report errors ), It's because of the parameters x
The default value is equal to another parameter y
, And then y
There is no statement yet , Belong to “ dead zone ”. If y
The default value of is x
, You can't report an error , Because at this time x
It has been declared that .
function bar(x = 2, y = x) {
return [x, y];
}
bar(); // [2, 2]
in addition , The following code will also report an error , And var
Different behavior .
// Don't complain
var x = x;
// Report errors
let x = x;
// ReferenceError: x is not defined
The above code reports an error , It's also because of the temporary dead zone . Use let
When variables are declared , As long as the variable is used before the declaration is complete , You're going to report a mistake . This is the case with the above line , In variables x
Before the execution of the declaration statement is completed , Just go and get it x
Value , Result in an error ”x Undefined “.
ES6 Temporary deadband and let
、const
Statement does not have variable promotion , Mainly to reduce runtime errors , Prevent using this variable before it is declared , Which leads to unexpected behavior . Such a mistake lies in ES5 It's very common , Now there's this rule , It's easy to avoid such mistakes .
All in all , The essence of a temporary dead zone is , As soon as you enter the current scope , The variable to be used already exists , But not available , Only wait until the line that declares the variable appears , To get and use this variable .
Duplicate statements are not allowed
let
Not allowed in the same scope , Repeatedly declare the same variable .
// Report errors
function func() {
let a = 10;
var a = 1;
}
// Report errors
function func() {
let a = 10;
let a = 1;
}
therefore , Parameters cannot be redeclared inside a function .
function func(arg) {
let arg;
}
func() // Report errors
function func(arg) {
{
let arg;
}
}
func() // Don't complain
Block level scope
Why a block level scope is needed ?
ES5 Only global scope and function scope , There is no block-level scope , This brings a lot of unreasonable scenes .
The first scenario , Inner variables may override outer variables .
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
The original meaning of the above code is ,if
The outer part of the code block uses the outer part tmp
Variable , Use inner layer inside tmp
Variable . however , function f
After execution , The output is undefined
, The reason is that the variables are increasing , Leading to inner tmp
Variables cover the outer layer tmp
Variable .
The second scenario , The loop variable used to count is leaked as a global variable .
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
In the above code , Variable i
It's only used to control the cycle , But at the end of the cycle , It's not gone , Leakage becomes a global variable .
ES6 Block level scope of
let
It's actually JavaScript Block-level scopes have been added .
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
The function above has two blocks of code , Variables are declared n
, Post run output 5. This means that the outer code block is not affected by the inner code block . If you use it both times var
Defining variables n
, The final output value is 10.
ES6 Allow any nesting of block level scopes .
{
{
{
{
{let insane = 'Hello World'}
console.log(insane); // Report errors
}}}};
The above code uses a five layer block level scope , Each layer is a separate scope . Layer 4 scope cannot read internal variables of layer 5 scope .
The inner scope can define variables of the same name in the outer scope .
{
{
{
{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};
The emergence of block level scopes , In fact, it makes it widely used for anonymous immediate function expression ( anonymous IIFE) It's no longer necessary .
// IIFE How to write it
(function () {
var tmp = ...;
...
}());
// Block level scope writing
{
let tmp = ...;
...
}
Block level scopes and function declarations
Can a function declare... In a block level scope ? This is a rather confusing question .
ES5 Regulations , Functions can only be declared in the top-level scope and function scope , Cannot declare... At block level scope .
// Situation 1
if (true) {
function f() {}
}
// Situation two
try {
function f() {}
} catch(e) {
// ...
}
The above two function declarations , according to ES5 The rules are all illegal .
however , Browsers don't follow this rule , To be compatible with old code , It also supports declaring functions in block level scopes , So both of the above can actually run , No mistake. .
ES6 Introduced block level scope , Explicitly allow functions to be declared in block level scopes .ES6 Regulations , In block scope , Function declaration statements behave like let
, Cannot be referenced outside the block level scope .
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// Repeat function declaration once f
function f() { console.log('I am inside!'); }
}
f();
}());
The above code is in ES5 Run in , You'll get “I am inside!”, Because in if
Function declared within f
Will be promoted to the function header , The actual running code is as follows .
// ES5 Environmental Science
function f() { console.log('I am outside!'); }
(function () {
function f() { console.log('I am inside!'); }
if (false) {
}
f();
}());
ES6 It's totally different , In theory, we will get “I am outside!”. Because the functions declared in the block level scope are similar to let
, No effect outside the scope . however , If you are ES6 Run the above code in the browser , It's a mistake , Why is that ?
// Browser's ES6 Environmental Science
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// Repeat function declaration once f
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
The above code is in ES6 Browser , All will report wrong. .
original , If the processing rule of the function declared in the block level scope is changed , Obviously it's going to have a big impact on old code . In order to reduce the incompatibility ,ES6 stay appendix B It says , Browser implementation can not follow the above rules , Have their own Behavior mode .
- Allow functions to be declared within a block level scope .
- Function declaration is similar to
var
, That is, it will be promoted to the head of the global scope or function scope . - meanwhile , Function declarations are also promoted to the head of the block level scope in which they reside .
Be careful , The above three rules are only for ES6 The browser implementation of , The implementation of other environments does not have to comply with , Still treat the function declaration of the block level scope as let
Handle .
According to these three rules , Browser's ES6 Environment , Functions declared within a block level scope , Behavior similar to var
Declared variables . The actual running code of the above example is as follows .
// Browser's ES6 Environmental Science
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
Considering that the behavior differences caused by the environment are too large , You should avoid declaring functions in block level scopes . If you really need , It should also be written as a function expression , Instead of function declaration statements .
// Function declaration statements inside the block level scope , Not recommended
{
let a = 'secret';
function f() {
return a;
}
}
// Inside the block level scope , Use function expressions first
{
let a = 'secret';
let f = function () {
return a;
};
}
in addition , There's another thing to pay attention to .ES6 The block level scope of must have braces , If there are no braces ,JavaScript The engine assumes that there is no block level scope .
// The first way to write it , Report errors
if (true) let x = 1;
// The second way , Don't complain
if (true) {
let x = 1;
}
In the above code , The first way is without braces , So there is no block level scope , and let
Can only appear at the top level of the current scope , So wrong reporting . The second way to write it is in braces , So block level scope is established .
So is function declaration , In strict mode , Functions can only be declared at the top level of the current scope .
// Don't complain
'use strict';
if (true) {
function f() {}
}
// Report errors
'use strict';
if (true)
function f() {}
const command
Basic usage
const
Declare a read-only constant . Once declared , You can't change the value of a constant .
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
The above code indicates that changing the value of a constant will result in an error .
const
Declared variable must not change value , It means ,const
Once a variable is declared , It must be initialized immediately , It cannot be left for later assignment .
const foo;
// SyntaxError: Missing initializer in const declaration
The code above indicates , about const
Come on , Only declare no assignment , You're going to report a mistake .
const
The scope of let
The same command : Valid only in the block level scope where the declaration is located .
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
const
The constant declared by the command is also not promoted , There is also a temporary dead zone , Can only be used after the declared position .
if (true) {
console.log(MAX); // ReferenceError
const MAX = 5;
}
The above code is constant MAX
Call... Before declaration , The result is wrong .
const
Declared constant , Also with the let
Same non repeatable statement .
var message = "Hello!";
let age = 25;
// The following two lines will be wrong
const message = "Goodbye!";
const age = 30;
The essence
const
Actually guaranteed , It's not that the value of a variable can't be changed , Instead, the memory address that the variable points to holds the same data . For simple types of data ( The number 、 character string 、 Boolean value ), The value is stored at the memory address that the variable points to , So it's equivalent to a constant . But for data of composite type ( Mainly objects and arrays ), The memory address that the variable points to , It's just a pointer to the actual data ,const
It can only be guaranteed that the pointer is fixed ( Always point to another fixed address ), As for whether the data structure it points to is variable , It's totally out of control . therefore , You have to be very careful when declaring an object as a constant .
const foo = {};
// by foo Add an attribute , Can succeed
foo.prop = 123;
foo.prop // 123
// take foo Point to another object , You're going to report a mistake
foo = {}; // TypeError: "foo" is read-only
In the above code , Constant foo
It stores an address , This address points to an object . It's just this address that's immutable , That can't leave foo
Point to another address , But the object itself is variable , So you can still add new properties to it .
Here's another example .
const a = [];
a.push('Hello'); // Executable
a.length = 0; // Executable
a = ['Dave']; // Report errors
In the above code , Constant a
Is an array , The array itself is writable , But if you assign another array to a
, You're going to report a mistake .
If you really want to freeze the object , You should use Object.freeze
Method .
const foo = Object.freeze({});
// In normal mode , The next line doesn't work ;
// Strict mode time , The bank will report a mistake
foo.prop = 123;
In the above code , Constant foo
Point to a frozen object , So adding new attributes doesn't work , Strict mode will also report errors .
In addition to freezing the object itself , Object's properties should also be frozen . Here's a function that freezes objects completely .
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
ES6 Six ways to declare variables
ES5 There are only two ways to declare variables :var
Command and function
command .ES6 In addition to adding let
and const
command , It will be mentioned later , Two other ways to declare variables :import
Command and class
command . therefore ,ES6 Altogether 6 Ways to declare variables .
Properties of the top-level object
Top objects , In browser environment, it means window
object , stay Node refer to global
object .ES5 In , The properties of the top-level object are equivalent to the global variables .
window.a = 1;
a // 1
a = 2;
window.a // 2
In the above code , Property assignment of top level object and global variable assignment , It's the same thing .
The properties of top-level objects are linked to global variables , Is considered to be JavaScript One of the biggest design failures of language . This kind of design brings a few big problems , First of all, we can't report an undeclared variable error at compile time , Only the runtime knows ( Because global variables can be created by the properties of top-level objects , And the creation of attributes is dynamic ); secondly , It's easy for programmers to unknowingly create global variables ( For example, typing mistakes ); Last , The properties of top-level objects can be read and written everywhere , This is very bad for modular programming . On the other hand ,window
Objects have entity meanings , Refers to the browser's window object , The top-level object is an object with entity meaning , It's also inappropriate .
ES6 To change that , On the one hand, it stipulates that , To maintain compatibility ,var
Command and function
Global variables declared by the command , It is still the property of the top-level object ; On the other hand, it stipulates that ,let
command 、const
command 、class
Global variables declared by the command , Properties that do not belong to the top-level object . in other words , from ES6 Start , Global variables will gradually decouple from the properties of the top-level object .
var a = 1;
// If in Node Of REPL Environmental Science , It can be written. global.a
// Or in a general way , It's written in this.a
window.a // 1
let b = 1;
window.b // undefined
In the above code , Global variables a
from var
A statement of order , So it's a property of the top-level object ; Global variables b
from let
A statement of order , So it's not a property of the top-level object , return undefined
.
globalThis object
JavaScript There is a top-level object in a language , It provides a global environment ( The global scope ), All the code runs in this environment . however , The top-level objects are not unified in various implementations .
- In browser , The top object is
window
, but Node and Web Worker No,window
. - The browser and Web Worker Inside ,
self
It also points to the top object , however Node No,self
. - Node Inside , The top object is
global
, But no other environment supports .
The same code in order to be able to be in various environments , Can get to the top object , Now it's commonly used this
keyword , But there are limitations .
- In a global environment ,
this
Will return the top object . however ,Node.js Modulethis
Back to the current module ,ES6 Modulethis
The return isundefined
. - Inside the function
this
, If a function does not run as a method of an object , It's just a function ,this
Will point to the top object . however , In strict mode , At this timethis
Returns theundefined
. - Whether it's a strict model , It's still the normal mode ,
new Function('return this')()
, Always return global objects . however , If the browser uses CSP(Content Security Policy, Content security policy ), thateval
、new Function
These methods may not work .
in summary , It's hard to find a way , In all cases , Take all the top objects . Here are two ways to use it .
// Method 1
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
// Method 2
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
ES2020 At the level of language standards , introduce globalThis
As a top-level object . in other words , In any environment ,globalThis
It's all there , You can get the top-level object from it , Point to... In the global environment this
.
Gasket Library global-this Simulated the proposal , You can get... In all environments globalThis
.
The above code ,i Yes, it is var Declarative , Valid globally , There is only one global variable i, Every cycle , Variable i The value of will change ,
Two 、 Object lexical extension 、 Structure of objects and arrays
Object extension
1、 The introduction of the attribute indicates ( Attribute shorthand , Method shorthand )
Practical example :
2、 Property name expression
The first method is to directly use the identifier as the attribute name , The second method is to use the expression as the attribute name ,
If you define an object literally ( Use braces ), stay ES5 Only method one can be used in ( identifier ) Defining attributes .
let propName = "value";
let obj = {
[propName]:true,
["one"+"child"]:1323
}
obj[propName] // true
obj[onechild] // 1323
Expressions can also be used to define method names .
- Be careful , Attribute name expression and concise representation , Can't be used at the same time , Will report a mistake .
// Report errors
const foo1 = 'bar1';
const bar1 = 'abc';
const baz1 = { [foo1] }
console.log(baz1,'baz1')
// correct
const foo2 = 'bar';
const baz = { [foo2]: 'abc'};
console.log(baz,'baz')
- If the property name expression is an object , By default, the object is automatically converted to a string
[object Object]
,
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
3、 Methodical name attribute
Functional name attribute , Return function name . Object methods are also functions , So there is name attribute .
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
If the method of the object uses the value function (getter) And the stored value function (setter),
be name Property is not on the method , But the properties of the method Describing the object get and set attribute above ,
The return value is the method name plus get and set.
const obj = {
get foo() {},
set foo(x) {}
};
obj.foo.name
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
There are two special cases :bind Method to create a function ,name Property returns bound Add the name of the original function ;Function Function created by constructor ,name Property returns anonymous.
4、 Enumerability and traversal of properties
Enumerability
Object.getOwnPropertyDescriptor
Method to get the description object for the property .
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
Describing the object enumerable
attribute , be called “ Enumerability ”, If the property is false
, It means that some operations will ignore the current property .
at present , There are four operations that will be ignored enumerable
by false
Properties of .
for...in
loop : Only traverse objects Self and inherited Enumerable properties .
for … in loop , It can loop all the attributes of an object in turn
var o = { name: 'Jack', age: 20, city: 'Beijing' }; for (var key in o) { console.log(key); // 'name', 'age', 'city' }
To filter out the inherited properties of an object , use hasOwnProperty() To achieve :var o = { name: 'Jack', age: 20, city: 'Beijing' }; for (var key in o) { if (o.hasOwnProperty(key)) { console.log(key); // 'name', 'age', 'city' } }
because Array Also object , And the index of each element is treated as an attribute of the object , therefore ,for … in Circulation can be directly circulated out Array The index of :
var a = ['A', 'B', 'C']; for (var i in a) { console.log(i); // '0', '1', '2' console.log(a[i]); // 'A', 'B', 'C' }
Please note that ,for … in Yes Array The result of the cycle is String instead of Number.
Object.keys()
: Returns the object All enumerable properties of itself Key name of .
let person = {name:" Zhang San ",age:25,address:" Shenzhen ",getName:function(){}} Object.keys(person).map((key)=>{ person[key] // Get the corresponding value of the attribute , Do something about it })
JSON.stringify()
: Serialize only the enumerable properties of the object itself .
(JS value =>JSON character string )
Object.assign()
: Ignoreenumerable
byfalse
Properties of , Copy only the enumerable properties of the object itself .
Object.assign()
Method to copy the values of all enumerable properties from one or more source objects to the target object . It will return the target object . Namely Object.assign() Is the static method of the object , Can be used to copy objects enumeration Attribute to target object , Using this feature, you can merge object properties .
Object.assign(target, ...sources)
Parameters :target---> Target audience
source---> Source object
Return value :target, That is, the target object
var target={name:'guxin',age:18}; var source={state:'single'} var result=Object.assign(target,source); console.log(target,target==result);
We can see source Upper state Properties merged into target On the object . If you just want to merge the properties of two or more objects together , Do not change the properties of the original object , You can use an empty object as target object . Like this :
var result=Object.assign({},target,source);
If there is an attribute with the same name , The following property values will override the previous property values .
matters needing attention :
1、Object.assign Method copies only the properties of the source object itself and can be enumerated to the target object , Inherited properties and enumerable properties cannot be copied .
2、 For deep copy , Other methods are needed , because Object.assign() Copied property values . If the property value of the source object is a reference to an object , Then it only points to the reference .
3、 The target object itself will change
4、 Exceptions interrupt subsequent copy tasks
And $.extend() Except for compatibility, it should be the same .
among , Only for...in
Will return the inherited properties , The other three methods ignore inherited properties , Only handle the properties of the object itself . actually , introduce “ enumerable ”(enumerable
) The original purpose of this concept , Is to let some attributes be avoided for...in
operation , Otherwise, all internal properties and methods will be traversed to . such as , Object archetypal toString
Method , And the array length
attribute , Just through “ Enumerability ”, To avoid being for...in
Traversing .
Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false
Object.getOwnPropertyDescriptor([], 'length').enumerable
// false
In the above code ,toString
and length
Attribute enumerable
All are false
, therefore for...in
These two properties inherited from the prototype will not be traversed .
ES6 Regulations , all Class The prototype methods are enumerable .
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable//false
in general , The introduction of inherited properties in the operation will complicate the problem , Most of the time , We only care about the properties of the object itself . therefore , Try not to use for...in
loop , While using Object.keys()
Instead of .
5、 Property traversal
(1)for...in
for...in
Loop through the object's own and inherited enumerable properties ( Not included Symbol attribute ).
(2)Object.keys(obj)
Object.keys
Returns an array , Including the object itself ( Without inheritance ) All enumerable properties ( Not included Symbol attribute ) Key name of .
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
Returns an array , Contains all the properties of the object itself ( Not included Symbol attribute , But include enumerable properties ) Key name of .
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
Returns an array , Contains all of the object itself Symbol The key name of the property .
(5)Reflect.ownKeys(obj)
Reflect.ownKeys
Returns an array , That contains the object itself ( Without inheritance ) All key names , Whatever the key name is Symbol Or a string , It doesn't matter whether it's enumerable or not .
The above 5 One way to traverse the key name of an object , All follow the same property traversal order rules .
- First, traverse all numeric keys , Arrange in ascending numerical order .
- Second, traverse all string keys , In ascending order of joining time .
- Finally, traverse all Symbol key , In ascending order of joining time .
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]
Reflect.ownKeys
Method returns an array , Contains all the properties of the parameter object . The property order of this array is as follows , The first is the numeric property 2
and 10
, The second is the string attribute b
and a
, And finally Symbol attribute .
6、super keyword
We know ,this
Keywords always point to Where is the function The current object of ,ES6 Another similar keyword has been added super
, Point to The current object Of Prototype object .
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
In the above code , object obj.find()
Among methods , adopt super.foo
Reference to prototype object proto
Of foo
attribute .
Be careful ,super
When the keyword represents a prototype object , It can only be used in the method of object , It's wrong to use it in other places .
// Report errors
const obj = {
foo: super.foo
}
// Report errors
const obj = {
foo: () => super.foo
}
// Report errors
const obj = {
foo: function () {
return super.foo
}
}
The three above super
The usage of will report errors , Because for JavaScript For the engine , there super
Not used in object methods . The first is super
Used in properties , The second and third ways of writing are super
Used in a function , And then assign it to foo
attribute . at present , Only The abbreviation of object method can make JavaScript The engine confirms , What is defined is the method of the object .
JavaScript Inside the engine ,super.foo
Equate to Object.getPrototypeOf(this).foo
( attribute ) or Object.getPrototypeOf(this).foo.call(this)
( Method ).
const proto = {
x: 'hello',
foo() {
console.log(this.x);
},
};
const obj = {
x: 'world',
foo() {
super.foo();
}
}
Object.setPrototypeOf(obj, proto);
obj.foo() // "world"
In the above code ,super.foo
Point to the prototype object proto
Of foo
Method , But bound this
But it's still the current object obj
, So the output is world
.
6、 Object's extension operator
Deconstruct assignment
The copy of the deconstruction assignment is a shallow copy , That is, if the value of a key is a value of composite type ( Array 、 object 、 function )、 So what we deconstruct the assignment copy is the reference of this value , Not a copy of this value .
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
In the above code ,x
Is the object that deconstructs the assignment , Copied the object obj
Of a
attribute .a
Property refers to an object , Modify the value of this object , It will affect the reference of deconstruction assignment to it .
in addition , Deconstruction assignment of extension operators , Properties inherited from prototype objects cannot be copied .
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
In the above code , object o3
Copy the o2
, But only copied o2
Properties of itself , There is no prototype object to copy it o1
Properties of .
const o = Object.create({ x: 1, y: 2 });
o.z = 3;
let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1
y // undefined
z // 3
In the above code , Variable x
It's a simple deconstruction assignment , So you can read objects o
Inherited properties ; Variable y
and z
Is the deconstruction assignment of the extension operator , Only objects can be read o
Properties of itself , So the variable z
You can assign success , Variable y
Can 't get value .ES6 Regulations , Variable declaration statement , If deconstruction assignment is used , The extension operator must be followed by Variable name , and It cannot be a deconstruction assignment expression , So the above code introduces intermediate variables newObj
, If it is written below, it will report an error .
let { x, ...{ y, z } } = o;
// SyntaxError: ... must be followed by an identifier in declaration contexts
One use of deconstruction assignment , Is an argument that extends a function , Introduce other operations .
function baseFunction({ a, b }) {
// ...
}
function wrapperFunction({ x, y, ...restConfig }) {
// Use x and y Parameters
// The remaining parameters are passed to the original function
return baseFunction(restConfig);
}
In the above code , Primitive functions baseFunction
Accept a
and b
As a parameter , function wrapperFunction
stay baseFunction
On the basis of this, we extend it , Can accept redundant parameters , And preserve the behavior of the original function .
Extension operator
Object's extension operator (...
) Used to fetch all traversable properties of parameter object , Copy to current object .
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
Because arrays are special objects , So the extension operator of the object can also be used for arrays .
let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
If the extension operator is followed by an empty object , There is no effect .
{...{}, a: 1}
// { a: 1 }
If the extension operator is not followed by an object , It will be automatically converted to an object .
// Equate to {...Object(1)}
{...1} // {}
In the above code , The extension operator is followed by an integer 1
, A wrapper object that is automatically converted to a numeric value Number{1}
. Because the object does not have its own properties , So return an empty object .
The following examples are similar .
// Equate to {...Object(true)}
{...true} // {}
// Equate to {...Object(undefined)}
{...undefined} // {}
// Equate to {...Object(null)}
{...null} // {}
however , If the extension operator is followed by a string , It will automatically turn into an array like object , Therefore, the returned object is not empty .
{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
Object's extension operator , Only the... Of the parameter object itself will be returned 、 Enumerable properties , Be very careful about this , Especially for instance objects of classes .
class C {
p = 12;
m() {}
}
let c = new C();
let clone = { ...c };
clone.p; // ok
clone.m(); // Report errors
In the above example ,c
yes C
class , When expanding it , Will only return c
Properties of itself c.p
, Instead of going back c
Methods c.m()
, Because this method is defined in C
On the prototype object ( See Class Chapter of ).
Object's extension operator is equivalent to using Object.assign()
Method .
let aClone = { ...a };
// Equate to
let aClone = Object.assign({}, a);
The above example just copies the properties of the object instance , If you want to clone an object completely , Also copy the properties of the object prototype , It can be written in the following way .
// Writing a
const clone1 = {
__proto__: Object.getPrototypeOf(obj),
...obj
};
// Write two
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
);
// Write three
const clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)
In the above code , In one way __proto__
Properties are not necessarily deployed in a non browser environment , Therefore, it is recommended to use writing method 2 and writing method 3 .
Extension operators can be used to merge two objects .
let ab = { ...a, ...b };
// Equate to
let ab = Object.assign({}, a, b);
If user-defined properties , After the extension operator , Then the attribute with the same name inside the extension operator will be overwritten .
let aWithOverrides = { ...a, x: 1, y: 2 };
// Equate to
let aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
// Equate to
let x = 1, y = 2, aWithOverrides = { ...a, x, y };
// Equate to
let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
In the above code ,a
Object's x
Properties and y
attribute , After copying to a new object, it will be overwritten .
This is convenient to modify the properties of existing object parts .
let newVersion = {
...previousVersion,
name: 'New Name' // Override the name property
};
In the above code ,newVersion
Object is customized name
attribute , All other properties are copied from previousVersion
object .
If you put the custom attribute before the extension operator , It becomes to set the default property value of the new object .
let aWithDefaults = { x: 1, y: 2, ...a };
// Equate to
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
// Equate to
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
Like the expansion operator of an array , The extension operator of an object can be followed by an expression .
const obj = {
...(x > 1 ? {a: 1} : {}),
b: 2,
};
The parameter object of the extension operator , If there is a value function get
, This function will execute .
let a = {
get x() {
throw new Error('not throw yet');
}
}
let aWithXGetter = { ...a }; // Report errors
In the example above , Value function get
Expanding a
Object is automatically executed , Result in an error .
7、AggregateError Error object
ES2021 In the standard , in order to With the new Promise.any()
Method ( See 《Promise object 》 chapter ), It also introduces a new Error object AggregateError
, It is also introduced in this chapter .
AggregateError In a wrong object , Encapsulates multiple errors . If a single operation , Multiple errors were raised at the same time , You need to throw these errors at the same time , Then you can throw a AggregateError Error object , Put all kinds of errors in this object .
AggregateError Itself a constructor , Used to generate AggregateError Instance object .
AggregateError(errors[, message])
AggregateError()
The constructor can accept two parameters .
- errors: Array , Each of its members is an error object . This parameter is required .
- message: character string , Express AggregateError Prompt message when thrown . This parameter is optional .
const error = new AggregateError([
new Error('ERROR_11112'),
new TypeError('First name must be a string'),
new RangeError('Transaction value must be at least 1'),
new URIError('User profile link must be https'),
], 'Transaction cannot be processed')
In the above example ,AggregateError()
In the first parameter array of , There are four error instances . The second parameter string is an overall hint of these four errors .
AggregateError
The instance object of has three properties .
- name: Wrong name , The default is “AggregateError”.
- message: Wrong message .
- errors: Array , Each member is an error object .
Here's an example .
try {
throw new AggregateError([
new Error("some error"),
], 'Hello');
} catch (e) {
console.log(e instanceof AggregateError); // true
console.log(e.message); // "Hello"
console.log(e.name); // "AggregateError"
console.log(e.errors); // [ Error: "some error" ]
}
8、Error Object's cause attribute
Error Object is used to represent the exception of code runtime , But the context information obtained from this object , Sometimes it's hard to interpret , Not enough .ES2022 by Error Object added a cause
attribute , You can generate errors , Add a description of the reason for the error .
Its usage is new Error()
Generate Error When an instance , Give a description object , This object can be set cause
attribute .
const actual = new Error('an error!', { cause: 'Error cause' });
actual.cause; // 'Error cause'
In the above example , Generate Error When an instance , Use the description object to give cause
attribute , Write the reason for the error . then , You can read this attribute from the instance object .
casue
Property can place any content , It doesn't have to be a string .
try {
maybeWorks();
} catch (err) {
throw new Error('maybeWorks failed!', { cause: err });
}
In the above example ,cause
Property is an object .
边栏推荐
- Nucleic acid scanning code registration experience (how to improve the correct character recognition rate of OCR)
- How does alternates achieve high-performance publish and subscribe?
- 附录2-一些简单的练习
- 【C语言】三子棋(智能下棋 + 阻拦玩家)
- View port occupancy
- 网络安全(5)
- How to introduce your project experience?
- Handwritten character recognition
- 基于C语言模拟实现DFA识别字符串
- 《UnityShader入门精要》总结(2):初级篇
猜你喜欢
【C语言】三子棋(智能下棋 + 阻拦玩家)
存算一体与存内计算计算杂谈
23考研人撑住!考研第一波弃考高峰期已经到来!
引入redis缓存出现的问题以及解决方式
当 update 修改数据与原数据相同时会被更新吗?
Behind 100000 visits...
23 postgraduate entrance examination people hold on! The first wave of exam abandonment peak has arrived!
怎么样的框架对于开发者是友好的?
远程连接windows版本服务器redis的配置文件设置
[machine learning] logistic regression code exercise
随机推荐
远程连接windows版本服务器redis的配置文件设置
A structured random inactivation UNET for retinal vascular segmentation
How to contribute to openharmony
详解:到底什么是GPS北斗授时服务器?
vector实现
Unity Xchart3.0基本用法快速上手
How to introduce your project experience?
Visual Studio
[machine learning] logistic regression code exercise
Random number setting and reference between parameters
23考研人撑住!考研第一波弃考高峰期已经到来!
redis命令[逐渐完善]
Nutnews developed based on arkui ETS
网络安全(5)
[Apple Developer account]06 after transferring the developer account, the annual fee of the developer is automatically renewed
【C语言】三子棋(智能下棋 + 阻拦玩家)
文件重命名后,怎样将新旧文件名及所在位置导出到excel
一知半解 ~题目杂记 ~ 一个多态问题
手动从0搭建ABP框架-ABP官方完整解决方案和手动搭建简化解决方案实践
On contract testing