Let and const commands

  • letA declared variable is valid only in the block of code in which it exists.
  • forAnother special feature of the loop is that the part that sets the variables of the loop is a parent scope, while the inside of the loop body is a separate child scope
  • There are six ways to declare variables in ES6:var.function.let.const.import.class
  • varCommands andfunctionGlobal variables declared by commands are still attributes of top-level objects; On the other hand,letThe command,constThe command,classThe global variable declared by the command is not an attribute of the top-level object. That is, starting with ES6, global variables will gradually be decoupled from the properties of top-level objects.
  • ES2020At the level of language standards, introductionglobalThisAs the top-level object. That is to say, in any situation,globalThisIt’s all there

2. Deconstruction assignment of variables

1. Array deconstruction assignment

let [a, b, c] = [1.2.3];

let [x, , y] = [1.2.3];
x / / 1
y / / 3

let [head, ...tail] = [1.2.3.4];
head / / 1
tail / / [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z / / []
Copy the code

Any data structure that has an Iterator interface can take the form of an array of destructively assigned values.

let [x, y, z] = new Set(['a'.'b'.'c']);
x // "a"
Copy the code

The default value

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a'.undefined]; // x='a', y='b'
Copy the code

ES6 internally uses the strict equality operator (===) to determine whether a position has a value. Therefore, the default value is valid only if an array member is strictly equal to undefined.

let [x = 1] = [undefined];
x / / 1

let [x = 1] = [null];
x // null
Copy the code

The array member in the above code is null and the default value does not take effect

2. Structure assignment of the object

Object structure

let { foo, bar } = { foo: 'aaa'.bar: 'bbb' };
foo // "aaa"
bar // "bbb"
Copy the code

If deconstruction fails, the value of the variable is equal to undefined

Structure assignment redeclares variables

let { foo: baz } = { foo: 'aaa'.bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
Copy the code

Like arrays, deconstruction can also be used for nested structured objects.

let obj = {
  p: [
    'Hello',
    { y: 'World'}};let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
Copy the code

The default value

var {x = 3} = {};
x / / 3

var {x, y = 5} = {x: 1};
x / / 1
y / / 5

var {x: y = 3} = {};
y / / 3

var {x: y = 3} = {x: 5};
y / / 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
Copy the code

The default is valid only if the object’s attribute value is strictly equal to undefined.

var {x = 3} = {x: undefined};
x / / 3

var {x = 3} = {x: null};
x // null
Copy the code

In the code above, the attribute x is null, and since null is not exactly equal to undefined, it is a valid assignment, causing the default value 3 not to take effect

3. String structure assignment

Strings can also deconstruct assignments. This is because at this point, the string is converted to an array-like object.

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
Copy the code

Array-like objects have a length attribute, so you can also deconstruct and assign to this attribute.

let {length : len} = 'hello';
len / / 5
Copy the code

4. Deconstructive assignment of values and Bores

When deconstructing an assignment, if the value and Boolean are to the right of the equals sign, the object is converted first.

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true
Copy the code

In the code above, both numeric and boolean-wrapped objects have toString attributes, so the variable S can take a value.

The rule for deconstructing assignment is to turn the value to the right of the equals sign into an object whenever it is not an object or array. Undefined and NULL cannot be converted to objects, so destructuring assignments to them will result in an error.

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
Copy the code

5. Destruct assignment of function parameters

Function arguments can also be destructively assigned.

function add([x, y]){
  return x + y;
}

add([1.2]); / / 3
Copy the code

In the above code, the arguments to the function add are ostensibly an array, but the moment they are passed in, the array arguments are resolved to form variables X and y. For the code inside the function, the arguments it senses are x and y.

[[1.2], [3.4]].map(([a, b]) = > a + b);
// [3, 7]
Copy the code

String extension

1. Unicode representation of characters

ES6 has enhanced Unicode support, allowing a character to be represented in the \uxxxx form, where XXXX represents the Unicode code point of the character.

"\u0061"
// "a"
Copy the code

However, this representation is limited to characters with code points between \u0000 and \uFFFF. Characters outside this range must be represented as two double bytes.

"\uD842\uDFB7"
/ / "𠮷"

"\u20BB7"
// " 7"
Copy the code

The code above shows that JavaScript will interpret \u20BB+7 as \u20BB+7 if you directly follow \u with a value greater than 0xFFFF (such as \u20BB7). Since \u20BB is a non-printable character, only a space is displayed, followed by a 7.

ES6 improves on this by putting the code point in braces to read the character correctly.

"\u{20BB7}"
/ / "𠮷"

"\u{41}\u{42}\u{43}"
// "ABC"

let hello = 123;
hell\u{6F} / / 123

'\u{1F680}'= = ='\uD83D\uDE80'
// true
Copy the code

The last example in the above code shows that the curly brace notation is equivalent to the four-byte UTF-16 encoding.

With this notation, there are six ways that JavaScript can represent a character.

'\z'= = ='z'  // true
'\ 172'= = ='z' // true
'\x7A'= = ='z' // true
'\u007A'= = ='z' // true
'\u{7A}'= = ='z' // true
Copy the code

2. String traverser interface

ES6 adds a traverser interface for strings (see chapter Iterator), which allows strings to be used for… The of loop traverses.

for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"
Copy the code

3. Enter U+2028 and U+2029

JavaScript requires five characters, which cannot be used directly in a string, but can only be escaped.

  • U+005C: Backslash (reverse solidus)
  • U+000D: carriage return
  • U+2028: Line separator
  • U+2029: Paragraph separator
  • U+000A: Line feed

4. Template string

console.log('This is the inverted quotation mark: \' \ 'Yo\' World! `.trim());

let x = 1;
let y = 2;

`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"

`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"

let obj = {x: 1.y: 2};
`${obj.x + obj.y}`
/ / "3"

function fn() {
  return "Hello World";
}

`foo ${fn()} bar`
// foo Hello World bar
Copy the code

4, string new method

1.String.fromCodePoint()

ES5 provides the string.fromCharCode () method for returning corresponding characters from Unicode code points, but this method does not recognize characters with code points greater than 0xFFFF.

ES6 provides the string.fromCodePoint () method, which can recognize characters larger than 0xFFFF, compensating for the string.fromCharcode () method. In effect, this is the opposite of the codePointAt() method below.

String.fromCodePoint(0x20BB7)
/ / "𠮷"
String.fromCodePoint(0x78.0x1f680.0x79) = = ='x\uD83D\uDE80y'
// true
Copy the code

In the above code, if the String.fromCodePoint method has multiple arguments, they are returned as a single String.

Note that the fromCodePoint method is defined on a String, while the codePointAt method is defined on an instance of a String.

2.String.raw()

This method returns a string in which all slashes have been escaped (that is, a slash followed by another slash), often used in template string processing

String.raw`Hi\nThe ${2+3}! `
// Actually returns "Hi\\n5!" , displays the escaped result "Hi\n5!"

String.raw`Hi\u000A! `;
// Actually returns "Hi\\u000A!" , displays the escaped result "Hi\u000A!"
Copy the code

String.raw() is essentially a normal function, just a label function dedicated to template strings. If written as a normal function, its first argument should be an object with a RAW attribute, and the RAW attribute value should be an array of parsed values for the template string.

// `foo${1 + 2}bar`
/ / is equivalent to
String.raw({ raw: ['foo'.'bar']},1 + 2) // "foo3bar"
Copy the code

In the above code, the first argument to the string.raw () method is an object whose RAW property is equivalent to the array parsed from the original template String.

As a function, the code for String.raw() is basically as follows.

String.raw = function (strings, ... values) {
  let output = ' ';
  let index;
  for (index = 0; index < values.length; index++) {
    output += strings.raw[index] + values[index];
  }

  output += strings.raw[index]
  return output;
}
Copy the code

3. Example method: codePointAt()

The codePointAt() method correctly returns the 32-bit utF-16 character code point. For regular two-byte characters, it returns the same result as the charCodeAt() method.

The codePointAt() method returns the decimal value of the codepoint, which can be converted using the toString() method if you want a hexadecimal value.

let s = '𠮷 a';

s.codePointAt(0).toString(16) // "20bb7"
s.codePointAt(2).toString(16) / / "61"
Copy the code

4. Example methods: includes(), startsWith(), endsWith()

  • Includes () : Returns a Boolean value indicating whether the parameter string was found.
  • StartsWith () : Returns a Boolean value indicating whether the argument string is at the head of the original string.
  • EndsWith () : Returns a Boolean value indicating whether the argument string is at the end of the original string.
let s = 'Hello world! ';

s.startsWith('Hello') // true
s.endsWith('! ') // true
s.includes('o') // true
Copy the code

All three of these methods support a second parameter indicating where the search begins.

let s = 'Hello world! ';

s.startsWith('world'.6) // true
s.endsWith('Hello'.5) // true
s.includes('Hello'.6) // false
Copy the code

The code above shows that with the second argument n, endsWith behaves differently from the other two methods. It works for the first n characters, while the other two work from the NTH position to the end of the string.

5. Instance method: repeat()

The repeat method returns a new string, repeating the original string n times.

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) / / ""
Copy the code

The argument is rounded if it is a decimal.

'na'.repeat(2.9) // "nana"
Copy the code

If the repeat argument is negative or Infinity, an error is reported.

'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
Copy the code

However, if the argument is a decimal between 0 and -1, it is the same as 0 because the round is performed first. If the decimal number between 0 and -1 is rounded to -0, repeat is regarded as 0.

'na'.repeat(-0.9) / / ""
Copy the code

The NaN argument is equal to 0.

'na'.repeat(NaN) / / ""
Copy the code

If the argument of the repeat is a string, it is converted to a number first.

'na'.repeat('na') / / ""
'na'.repeat('3') // "nanana"
Copy the code

6. Instance methods: padStart(), padEnd()

ES2017 introduces the function of string completion length. If a string is not of a specified length, the header or tail is completed. PadStart () is used for head completion and padEnd() for tail completion.

'x'.padStart(5.'ab') // 'ababx'
'x'.padStart(4.'ab') // 'abax'

'x'.padEnd(5.'ab') // 'xabab'
'x'.padEnd(4.'ab') // 'xaba'
Copy the code

In the code above, padStart() and padEnd() take two arguments. The first argument is the maximum length that string completion takes effect, and the second argument is the string used for completion.

If the length of the original string is equal to or greater than the maximum length, the string completion does not take effect and the original string is returned.

'xxx'.padStart(2.'ab') // 'xxx'
'xxx'.padEnd(2.'ab') // 'xxx'
Copy the code

If the sum of the length of the completion string and the original string exceeds the maximum length, the completion string with more than bits is truncated.

'abc'.padStart(10.'0123456789')
// '0123456abc'
Copy the code

If the second argument is omitted, Spaces are used to complete the length by default.

'x'.padStart(4) // ' x'
'x'.padEnd(4) // 'x '
Copy the code

A common use of padStart() is to specify bits for numeric completion. The following code generates a 10-digit numeric string.

'1'.padStart(10.'0') / / "0000000001"
'12'.padStart(10.'0') / / "0000000012"
'123456'.padStart(10.'0') / / "0000123456"
Copy the code

Another use is the prompt string format.

'12'.padStart(10.'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10.'YYYY-MM-DD') // "YYYY-09-12"
Copy the code

7. Example methods: trimStart(), trimEnd()

const s = ' abc ';

s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
Copy the code

Example method: replaceAll()

'aabbcc'.replaceAll('b'.'_')
// 'aa__cc'
Copy the code

The second argument to replaceAll(), replacement, is a string representing the text of the replacement, where special strings can be used.

  • $&: Matched substring.
  • $‘: matches the text before the result.
  • $': Matches the text following the result.
  • $n: Indicates the number that matches successfullynSet of content,nIt’s a natural number starting at 1. This parameter is valid only if the first parameter is a regular expression.
  • $$: indicates the dollar sign$.
/ $& indicates the matching string, that is`b`itself// So the result is the same as the original string
'abbc'.replaceAll('b'.'$&')
// 'abbc'

// $' represents the string before the result of the match
// For the first 'b', $' refers to 'a'
// For the second 'b', $' refers to 'ab'
'abbc'.replaceAll('b'.'$`)
// 'aaabc'

// $' represents the string following the result of the match
// For the first 'b', $' refers to 'BC'
// For the second 'b', $' refers to 'c'
'abbc'.replaceAll('b'.` $' `)
// 'abccc'

// $1 represents the first group match of the regular expression, indicating 'ab'
// $2 represents the second group match of the regular expression, which refers to 'BC'
'abbc'.replaceAll(/(ab)(bc)/g.'$2 $1')
// 'bcab'

// $$indicates $
'abc'.replaceAll('b'.'$$')
// 'a$c'
Copy the code

In addition to being a string, the second argument to replaceAll() can be a function whose return value replaces the text matched by the first argument searchValue.

'aabbcc'.replaceAll('b'.() = > '_')
// 'aa__cc'
Copy the code

This substitution function can take multiple arguments. The first parameter is the captured match, and the second parameter is the captured group match (there are as many parameters as there are group matches). In addition, two parameters can be added at the end, the penultimate being the position of the captured content in the entire string, and the last being the original string.

const str = '123abc456';
const regex = /(\d+)([a-z]+)(\d+)/g;

function replacer(match, p1, p2, p3, offset, string) {
  return [p1, p2, p3].join(The '-');
}

str.replaceAll(regex, replacer)
// 123 - abc - 456
Copy the code

In the example above, the regular expression has three group matches, so the first argument to the replacer() function match is the captured match (string 123abc456), followed by p1, P2, and p3.

5. Extension of re

1.RegExp constructor

In the first case, the argument is a string, in which case the second argument represents the regular expression modifier (flag).

var regex = new RegExp('xyz'.'i');
/ / equivalent to the
var regex = /xyz/i;
Copy the code

In the second case, if the argument is a regular expression, a copy of the original regular expression is returned.

var regex = new RegExp(/xyz/i);
/ / equivalent to the
var regex = /xyz/i;
Copy the code

If the first argument to the RegExp constructor is a regular object, the second argument can be used to specify the modifier. Furthermore, the returned regular expression ignores the modifier of the original regular expression and uses only the newly specified modifier.

new RegExp(/abc/ig.'i').flags
// "i"
Copy the code

In the code above, the modifier of the original re object is ig, which is overridden by the second argument I.

2. String regex method

ES6 uses these four methods to call RegExp instance methods within the language, so that all reged-related methods are defined on RegExp objects.

  • String.prototype.matchcallRegExp.prototype[Symbol.match]
  • String.prototype.replacecallRegExp.prototype[Symbol.replace]
  • String.prototype.searchcallRegExp.prototype[Symbol.search]
  • String.prototype.splitcallRegExp.prototype[Symbol.split]

3. U modifier

ES6 adds the U modifier to regular expressions, which stands for “Unicode mode” to properly handle Unicode characters larger than \uFFFF. That is, four bytes of UTF-16 encoding will be handled correctly.

/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
Copy the code

(1) dot character

Dot (.) Character in a regular expression, a character is any single character except a newline character. For Unicode characters with code points greater than 0xFFFF, dot characters are not recognized and must be decorated with the U modifier.

var s = '𠮷';

$/ / ^.test(s) // false
/^.$/u.test(s) // true
Copy the code

The code above shows that if you do not add the U modifier, the regular expression will assume that the string is two characters and fail to match.

(2) Unicode character representation

ES6 added curly braces for Unicode characters, which must be recognized by the U modifier in the regular expression, otherwise it will be interpreted as a quantifier.

/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true
Copy the code

The code above shows that, without the u modifier, the regular expression will not recognize the \u{61} notation, only that it matches 61 consecutive U’s.

(3)

With the U modifier, all quantifiers correctly recognize Unicode characters with code points greater than 0xFFFF.

/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true/ 𠮷 {2}/.test('𠮷 𠮷') // false/ 𠮷 {2}/u.test('𠮷 𠮷') // true
Copy the code

(4) Predefined mode

The u modifier also affects the predefined schema’s ability to correctly recognize Unicode characters with code points greater than 0xFFFF.

/^\S$/.test('𠮷') // false
/^\S$/u.test('𠮷') // true
Copy the code

The \S of the code above is a predefined pattern that matches all non-whitespace characters. It can correctly match Unicode characters with code points greater than 0xFFFF only if the u modifier is added.

Using this, you can write a function that returns the correct length of the string.

(5) I modifier

Some Unicode characters have different encodings but similar fonts, for example, \u004B and \u212A are capitalized K.

/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true
Copy the code

In the above code, the non-standard K character cannot be recognized without the u modifier.

(6) Escape

In the absence of the U modifier, escapes that are not defined in the re (such as the escape of the comma \,) are invalid, and errors are reported in U mode.

/ /,/ // /\, //\,/u / / an error
Copy the code

In the code above, the backslash before the comma is invalid without the u modifier, and an error is reported if the u modifier is added.

4. The RegExp. Prototype. Unicode attributes

A Unicode attribute is added to the re instance object indicating whether the U modifier is set.

const r1 = /hello/;
const r2 = /hello/u;

r1.unicode // false
r2.unicode // true
Copy the code

5. Y modifier

ES6 also adds a Y modifier to regular expressions, called the “sticky” modifier.

The y modifier is similar to the G modifier in that it is a global match, and each subsequent match starts at the position following the last successful match. The difference is that the G modifier works as long as there is a match in the remaining position, while the Y modifier ensures that the match must start at the first remaining position, which is what “bonding” means.

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;

r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]
r2.exec(s) // null
Copy the code

The Y modifier requires that the match must start at the head, so null is returned.

In fact, the y modifier implies the header matching flag ^.

const REGEX = /a/gy;
'aaxa'.replace(REGEX, The '-') // '--xa'
Copy the code

A single Y modifier for the match method returns only the first match, and must be combined with the G modifier to return all matches.

'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
Copy the code

6.RegExp.prototype.sticky

Matching the Y modifier, ES6’s regular instance object has the sticky attribute, indicating whether the Y modifier is set.

var r = /hello\d/y;
r.sticky // true
Copy the code

7.RegExp.prototype.flags

// ES5 source attribute
// Returns the body of the regular expression
/abc/ig.source
// "abc"

// Flags attributes for ES6
// Returns the modifier of the regular expression
/abc/ig.flags
// 'gi'
Copy the code

8. S modifier: dotAll mode

In a regular expression, the point (.) Is a special character that represents any single character, with two exceptions. One is a four-byte UTF-16 character, which can be solved with the U modifier; The other is the line terminator character.

A line terminator is a character that indicates the end of a line. The following four characters are line terminators.

  • U+000A newline (\n)
  • U+000D Carriage return (\r)
  • U+2028 Line separator
  • U+2029 Separator

ES2018 introduces the S modifier so that. Can match any single character.

/foo.bar/s.test('foo\nbar') // true
Copy the code

This is called the dotAll pattern, where dots represent all characters. So, regular expressions also introduce a dotAll attribute that returns a Boolean value indicating whether the regular expression is in dotAll mode.

const re = /foo.bar/s;
// Another way to write it
// const re = new RegExp('foo.bar', 's');

re.test('foo\nbar') // true
re.dotAll // true
re.flags // 's'
Copy the code

The /s modifier and the multi-line modifier /m do not conflict. When used together,. Matches all characters, while ^ and $match the beginning and end of each line.

11. Named group matching

Regular expressions use parentheses for group matching.

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
Copy the code

In the code above, there are three sets of parentheses inside the regular expression. These three sets of matching results can be extracted using the exec method.

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; / / 1999
const month = matchObj[2]; / / 12
const day = matchObj[3]; / / 31
Copy the code

One problem with group matching is that the matching meaning of each group is not easy to see and can only be referenced with numeric ordinals (such as matchObj[1]), which must be changed when the order of the group changes.

const RE_DATE = / (? 
      
       \d{4})-(? 
       
        \d{2})-(? 
        
         \d{2})/
        
       
      ;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; / / "1999"
const month = matchObj.groups.month; / / "12"
const day = matchObj.groups.day; / / "31"
Copy the code

In the above code, “named group match” is inside the parentheses, and the pattern header is “question mark + Angle bracket + group name” (?

), which can then be referenced on the Groups attribute where the exec method returns the result. Meanwhile, numeric ordinal number (matchObj[1]) is still valid.

Deconstruct assignment and substitution

With named group matching, you can assign variables directly from the result of the match using deconstructed assignment.

let {groups: {one, two}} = / ^ (? 
      
       .*):(? 
       
        .*)$/u
       
      .exec('foo:bar');
one  // foo
two  // bar
Copy the code

For string substitution, use $< group name > to refer to the named group.

let re = / (? 
      
       \d{4})-(? 
       
        \d{2})-(? 
        
         \d{2})/u
        
       
      ;

'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
/ / '02/01/2015'
Copy the code

In the code above, the second argument to the replace method is a string, not a regular expression.

The second argument to the replace method can also be a function, which has the following sequence of arguments.

'2015-01-02'.replace(re, (
   matched, // The entire matching result is 2015-01-02
   capture1, // The first group matches 2015
   capture2, // The second group matches 01
   capture3, // The third group matches 02
   position, // Match position 0 at the beginning
   S, // The original string 2015-01-02
   groups {year, month, day}
 ) = > {
 let {day, month, year} = groups;
 return `${day}/${month}/${year}`;
});
Copy the code

12. Regular match index

const text = 'zabbcdef';
const re = /ab/;
const result = re.exec(text);

result.index / / 1
Copy the code

The return result has an index attribute that retrieves the start of the entire match

13.String.prototype.matchAll()

ES2020 increased String. Prototype. MatchAll () method, which can be a one-time remove all matching. However, it returns an Iterator, not an array.

const string = 'test1test2test3';
const regex = /t(e)(st(\d?) )/g;

for (const match of string.matchAll(regex)) {
  console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
Copy the code

MatchAll (regex) returns a traverser, so we can use for… Of loop out. The advantage of returning a traversal over an array is that the traversal is resource-efficient if the result of the match is a large array.

Iterator to array is very simple, using… The operator and array.from () method do the trick.

// Convert to an array
[...string.matchAll(regex)]

// Convert to an array
Array.from(string.matchAll(regex))
Copy the code

6. Numerical extension

Binary and octal representation

ES6 provides a new way to write binary and octal values, represented by prefixes 0b (or 0b) and 0O (or 0O), respectively.

0b111110111= = =503 // true
0o767= = =503 // true
Copy the code

If you want to decimal string values prefixed with 0b and 0o, use the Number method.

Number('0b111')  / / 7
Number('0o10')  / / 8
Copy the code

2.Number.isFinite(), Number.isNaN()

Number.isfinite () is used to check whether a Number isFinite, i.e., not Infinity.

Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
Copy the code

Note that number. isFinite returns false if the parameter type is not a Number.

Number.isnan () is used to check whether a value isNaN.

Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
Copy the code

If the parameter type is not NaN, number. isNaN always returns false.

They differ from the traditional global methods isFinite() and isNaN(), which call Number() to convert a non-numerical value to a numerical value and then judge, but these two new methods are only valid for numerical values. Number.isfinite () returns false for non-numeric values, number.isnan () returns true only for nans, false for non-nans.

isFinite(25) // true
isFinite("25") // true
Number.isFinite(25) // true
Number.isFinite("25") // false

isNaN(NaN) // true
isNaN("NaN") // true
Number.isNaN(NaN) // true
Number.isNaN("NaN") // false
Number.isNaN(1) // false
Copy the code

3.Number.parseInt(), Number.parseFloat()

ES6 migrates the global methods parseInt() and parseFloat() onto the Number object, leaving the behavior exactly the same.

// ES5
parseInt('12.34') / / 12
parseFloat('123.45 #') / / 123.45

// ES6
Number.parseInt('12.34') / / 12
Number.parseFloat('123.45 #') / / 123.45
Copy the code

The goal is to gradually reduce the global approach and make the language more modular.

4.Number.isInteger()

Number.isinteger () is used to determine whether a value is an integer.

Number.isInteger(25) // true
Number.isInteger(25.1) // false
Copy the code

Inside JavaScript, integers and floating point numbers are stored the same way, so 25 and 25.0 are treated as the same value.

Number.isInteger(25) // true
Number.isInteger(25.0) // true
Copy the code

If the argument is not a numeric value, number. isInteger returns false.

Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false
Copy the code

Note: Numeric values are stored in 64-bit double precision format, up to 53 binary bits (1 hidden bit and 52 significant bits). If the precision of the value exceeds this limit, the 54th and subsequent bits are discarded, in which case number. isInteger may misjudge.

Number.isInteger(3.0000000000000002) // true
Copy the code

In general, if high data accuracy is required, it is not recommended to use number.isINTEGER () to determine whether a value is an integer.

5.Number.EPSILON

Infinitesimal constant number.epsilon. According to the specification, it represents the difference between 1 and the smallest floating point number greater than 1.

For 64-bit floating-point numbers, the minimum floating-point number greater than 1 is equivalent to binary 1.00.. 001, 51 consecutive zeros after the decimal point. So when you subtract 1 from this, you get 2 to the minus 52.

Number.EPSILON === Math.pow(2, -52)
// true
Number.EPSILON
/ / 2.220446049250313 e-16
Number.EPSILON.toFixed(20)
/ / "0.00000000000000022204"
Copy the code

Number.epsilon is actually the minimum precision that JavaScript can represent. If the error is less than that, it is considered meaningless, that is, there is no error.

0.1 + 0.2
/ / 0.30000000000000004

0.1 + 0.2 - 0.3
E-17 / / 5.551115123125783

5.551115123125783 e-17.toFixed(20)
/ / '0.00000000000000005551'
Copy the code

The above code explains why comparing 0.1 + 0.2 with 0.3 gives false.

0.1 + 0.2= = =0.3 // false
Copy the code

6. Safe integers and number.isSafeINTEGER ()

The range of integers that JavaScript can accurately represent is between -2^53 and 2^53 (excluding the two endpoints), beyond which this value cannot be accurately represented.

Math.pow(2.53) / / 9007199254740992

9007199254740992  / / 9007199254740992
9007199254740993  / / 9007199254740992
Copy the code

7. Extension of the Math object

ES6 adds 17 new math-related methods to the Math object. All of these methods are static and can only be called on Math objects.

  • The math. trunc method is used to remove the fractional part of a number and return the integer part.

    Math.trunc(4.9) / / 4
    Math.trunc(-4.1) / / - 4
    Math.trunc(-0.1234) / / - 0
    Copy the code
  • The math. sign method is used to determine whether a number is positive, negative, or zero. For non-numeric values, they are converted to numeric values first.

    • Returns if the argument is a positive number+ 1;
    • If argument is negative, return- 1;
    • Argument 0, returns0;
    • Argument -0, returns0;
    • Other values, returnNaN.
  • Math.cbrt() is used to calculate the cube root of a number.

  • The math.clz32 () method converts the argument to a 32-bit unsigned integer and returns how many leading zeros there are in the 32-bit value.

· · · · · · · · · · · · · · · · · · · · · · · · · · ·

8. Exponential operators

ES2016 has a new index operator (**).

2支那2 / / 4
2支那3 / / 8
Copy the code
// Equivalent to 2 ** (3 ** 2)
2支那3支那2
/ / 512
Copy the code

In the above code, the second exponential operator is evaluated first, not the first.

The exponential operator can be combined with the equal sign to form a new assignment operator (**=).

let a = 1.5;
a **= 2;
// a = a * a;

let b = 4;
b **= 3;
// the same as b = b * b * b;
Copy the code

9.BigInt Data type

ECMAScript’s eighth data type. BigInt is only used to represent integers. There is no limit on the number of digits.

To distinguish BigInt from Number, data of type BigInt must be suffixed with n.

1234 // An ordinary integer
1234n // BigInt

// The BigInt operation
1n + 2n // 3n
Copy the code

BigInt can also be represented in a variety of bases, all with the suffix n.

0b1101n / / binary
0o777n / / octal
0xFFn // Hexadecimal
Copy the code

BigInt and plain integers are two different values, and they are not equal.

42n= = =42 // false
Copy the code

Typeof operator returns BigInt for data of type BigInt.

typeof 123n // 'bigint'
Copy the code

BigInt object

JavaScript natively provides BigInt objects that can be used as constructors to generate values of type BigInt. The conversion rules are basically the same as for Number(), which converts other types of values to BigInt.

BigInt(123) // 123n
BigInt('123') // 123n
BigInt(false) // 0n
BigInt(true) // 1n
Copy the code

Almost all numeric operators can be used in BigInt, with two exceptions.

  • Unsigned right shift operator>>>
  • Unary positive operator+

For the same reason, if a library function takes a parameter of type Number and returns a BigInt, an error is reported.

// This is not the case
Math.sqrt(4n) / / an error

// The correct way to write
Math.sqrt(Number(4n)) / / 2
Copy the code

7. Function extension

1. Default values of function parameters

function log(x, y = 'World') {
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello'.'China') // Hello China
Copy the code

Used in conjunction with destructively assigned default values

Parameter defaults can be used in conjunction with the default values of deconstructed assignments.

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) / / 1 5
foo({x: 1.y: 2}) / / 1. 2
Copy the code

As an exercise, what is the difference between the following two ways?

/ / write one
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

/ / write two
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
Copy the code

Both methods set default values for function parameters. The difference is that the default values of function parameters are empty objects, but the default values of object deconstruction assignment are set. The default value of the two function arguments is an object with specific properties, but the default value of the object’s destruct assignment is not set.

// The function has no arguments
m1() / / [0, 0]
m2() / / [0, 0]

// both x and y have values
m1({x: 3.y: 8}) / / [3, 8]
m2({x: 3.y: 8}) / / [3, 8]

// if x has a value and y has no value
m1({x: 3}) / / [3, 0]
m2({x: 3}) // [3, undefined]

// if x and y have no values
m1({}) / / (0, 0),
m2({}) // [undefined, undefined]

m1({z: 3}) / / [0, 0]
m2({z: 3}) // [undefined, undefined]
Copy the code

The length property of the function

When a default value is specified, the length property of the function returns the number of arguments for which no default value is specified. That is, the length attribute is distorted when a default value is specified.

(function (a) {}).length / / 1
(function (a = 5) {}).length / / 0
(function (a, b, c = 5) {}).length / / 2
Copy the code
(function(. args) {}).length / / 0
Copy the code

If the parameter to which the default value is set is not the last parameter, the length attribute does not count toward subsequent parameters.

(function (a = 0, b, c) {}).length / / 0
(function (a, b = 1, c) {}).length / / 1
Copy the code

application

Using parameter defaults, you can specify that a particular parameter must not be omitted, and if omitted, an error is thrown.

function throwIfMissing() {
  throw new Error('Missing parameter');
}

function foo(mustBeProvided = throwIfMissing()) {
  return mustBeProvided;
}

foo()
// Error: Missing parameter
Copy the code

The foo function in the above code, if called with no arguments, will call the default throwIfMissing function, throwing an error.

2. The rest parameters

ES6 introduces the REST parameter (of the form… Variable name), used to get extra arguments to a function so you don’t need to use the arguments object. The rest argument goes with a variable that puts the extra arguments into an array.

function add(. values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2.5.3) / / 10
Copy the code

3. Strict mode

Starting with ES5, functions can be set to strict mode internally.

function doSomething(a, b) {
  'use strict';
  // code
}
Copy the code

ES2016 has changed a bit, stating that functions cannot be explicitly set to strict mode internally if they use default values, destructed assignments, or extended operators. Otherwise, an error will be reported.

The reason for this is that strict patterns within functions apply to both function bodies and function parameters. However, when a function is executed, its arguments are executed first, and then its body. The only way to know whether arguments should be executed in strict mode is from the function body, but arguments should be executed before the function body.

4. The name attribute

The name attribute of a number that returns the function name of the function.

function foo() {}
foo.name // "foo"

var f = function () {};

// ES5
f.name / / ""

// ES6
f.name // "f"

(new Function).name // "anonymous"
Copy the code

5. Arrow function

var f = v= > v;

let getTempItem = id= > ({ id: id, name: "Temp" });
Copy the code

Use caution points

The arrow function has several uses with caution.

(1) The arrow function does not have its own this object (see below).

(2) Do not use it as a constructor, that is, do not use the new command on arrow functions, otherwise an error will be thrown.

(3) You can’t use arguments. This object does not exist in the function body. If you do, use the REST argument instead.

(4) Yield cannot be used, so arrow functions cannot be used as Generator functions.

It does not have its own this object; the internal this is the this in the upper scope of the definition

6. Tail-call optimization

When the last step in a function is to call another function.

function f(x){
  return g(x);
}
Copy the code

Tail Call optimization preserves only the call frames of the inner functions. If all functions are tail calls, then it is perfectly possible to have only one call frame item per execution, which would save a lot of memory. This is what tail-call optimization is all about.

function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();

/ / is equivalent to
function f() {
  return g(3);
}
f();

/ / is equivalent to
g(3);
Copy the code

Tail recursion

For tail recursion, however, because there is only one call frame, there is never a stack overflow error.

function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n - 1);
}

factorial(5) / / 120
Copy the code

The above code is a factorial function, calculate n factorial, need to save at most N call records, complexity O(n)

If rewritten to tail recursion, only one call record is retained, complexity O(1).

function factorial(n, total) {
  if (n === 1) return total;
  return factorial(n - 1, n * total);
}

factorial(5.1) / / 120
Copy the code

Functional programming has a concept called currying, which means converting a multi-argument function into a single-argument form. You can also use corrification here.

function factorial(n, total = 1) {
  if (n === 1) return total;
  return factorial(n - 1, n * total);
}

factorial(5) / / 120
Copy the code

Array extension

1. Extend the operator

console.log(1. [2.3.4].5)
// 1, 2, 3, 4, 5
Copy the code

Extended operators can also be followed by expressions.

const arr = [
  ...(x > 0 ? ['a'] : []),
  'b',];Copy the code

Extend the application of operators

(1) Copy array

const a1 = [1.2];
/ / write one
const a2 = [...a1];
/ / write two
const [...a2] = a1;
Copy the code

(2) Merge arrays

[...arr1, ...arr2, ...arr3]
Copy the code
const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true
Copy the code

In the above code, A3 and A4 are new arrays combined in two different ways, but their members are references to the original array members, which is a shallow copy.

(3) Combine with deconstruction assignment

Extension operators can be used in conjunction with destructuring assignments to generate arrays.

// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
Copy the code

(4) String

Extension operators can also turn strings into true arrays.

[...'hello']
// [ "h", "e", "l", "l", "o" ]
Copy the code

(5) Objects that implement the Iterator interface

(6) Map and Set structures, Generator functions

let map = new Map([[1.'one'],
  [2.'two'],
  [3.'three']]);let arr = [...map.keys()]; / / [1, 2, 3]
Copy the code

When the Generator function runs, it returns an traverser object, so extension operators can also be used.

const go = function* (){
  yield 1;
  yield 2;
  yield 3;
};

[...go()] / / [1, 2, 3]
Copy the code

2.Array.from()

The array. from method is used to convert two types of objects into true arrays: array-like objects and iterable objects (including the new ES6 data structures Set and Map).

let arrayLike = {
    '0': 'a'.'1': 'b'.'2': 'c'.length: 3
};

// ES5
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Copy the code

Array.from can convert any data structure that has an Iterator interface deployed into an Array.

Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']

let namesSet = new Set(['a'.'b'])
Array.from(namesSet) // ['a', 'b']
Copy the code

Any object with length can be converted to an Array by the array. from method, whereas the extension operator cannot.

Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
Copy the code

Array.from can also take a second argument, similar to the map method of arrays, that is used to process each element and place the value in the returned Array.

Array.from(arrayLike, x= > x * x);
/ / is equivalent to
Array.from(arrayLike).map(x= > x * x);

Array.from([1.2.3].(x) = > x * x)
/ / [1, 4, 9]
Copy the code
Array.from([1.2.3].(n) = > n || 0)
// [1, 0, 2, 0, 3]
Copy the code

Array.from() can turn various values into real arrays and also provides map functionality. What this really means is that as long as you have a raw data structure, you can manipulate its values and then transform them into a formal array structure, which in turn allows you to use a large number of array methods.

Array.from({ length: 2 }, () = > 'jack')
Copy the code

3.Array.of()

The array.of () method converts a set of values to an Array.

Array.of(3.11.8) / /,11,8 [3]
Array.of(3) / / [3]
Array.of(3).length / / 1
Copy the code

Array.of() can basically be used as an alternative to Array() or new Array(), and there is no overloading due to different parameters. It’s very uniform in its behavior.

Array.of() / / []
Array.of(undefined) // [undefined]
Array.of(1) / / [1]
Array.of(1.2) / / [1, 2]
Copy the code

4. Array instance copyWithin()

The copyWithin() method of an array instance, inside the current array, copies the specified member to another location (overwriting the original member) and returns the current array. That is, using this method, you modify the current array.

Array.prototype.copyWithin(target, start = 0, end = this.length)
Copy the code

It takes three arguments.

  • Target (required) : Replace data from this location. If it is negative, it is the reciprocal.
  • Start (Optional) : reads data from this position. The default value is 0. If the value is negative, it is calculated from the end.
  • End (Optional) : Stops reading data until this position, which is equal to the array length by default. If the value is negative, it is calculated from the end.
[1.2.3.4.5].copyWithin(0.3)
// [4, 5, 3, 4, 5]
Copy the code

The code above shows that the members from bit 3 to the end of the array (4 and 5) are copied to the position starting at bit 0, overwriting the original 1 and 2.

Here are some more examples.

// copy bit 3 to bit 0
[1.2.3.4.5].copyWithin(0.3.4)
// [4, 2, 3, 4, 5]

// -1 = -1; // -1 = -1
[1.2.3.4.5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]

// copy bit 3 to bit 0
[].copyWithin.call({length: 5.3: 1}, 0.3)
// {0: 1, 3: 1, length: 5}

// Copy bit 2 to the end of the array to bit 0
let i32a = new Int32Array([1.2.3.4.5]);
i32a.copyWithin(0.2);
// Int32Array [3, 4, 5, 4, 5]

// For platforms that do not deploy TypedArray's copyWithin method
// Use the following notation
[].copyWithin.call(new Int32Array([1.2.3.4.5]), 0.3.4);
// Int32Array [4, 2, 3, 4, 5]
Copy the code

5. Find () and findIndex() of array instances

The find method of an array instance, used to find the first array member that matches the criteria. Its argument is a callback function that is executed by all array members until the first member that returns true is found, and then returned. If there is no qualified member, undefined is returned.

[1.4, -5.10].find((n) = > n < 0)
Copy the code

The find callback takes three arguments, the current value, the current position, and the original array.

The findIndex method on an array instance is used much like the find method, returning the location of the first qualified array member, or -1 if all members fail.

[1.5.10.15].findIndex(function(value, index, arr) {
  return value > 9;
}) / / 2
Copy the code

Both methods can take a second argument that binds the this object of the callback function.

function f(v){
  return v > this.age;
}
let person = {name: 'John'.age: 20};
[10.12.26.15].find(f, person);    / / 26
Copy the code

6. Array instance fill()

The fill method fills an array with the given value.

['a'.'b'.'c'].fill(7)
/ / (7, 7, 7)

new Array(3).fill(7)
/ / (7, 7, 7)
Copy the code

The fill method can also accept a second and third parameters that specify where the fill starts and ends.

['a'.'b'.'c'].fill(7.1.2)
// ['a', 7, 'c']
Copy the code

7. Array instance entries(), keys() and values()

The only differences are that keys() is traversal of key names, values() is traversal of key values, and entries() is traversal of key value pairs.

for (let index of ['a'.'b'].keys()) {
  console.log(index);
}
/ / 0
/ / 1

for (let elem of ['a'.'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a'.'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"
Copy the code

8. Array instance includes()

The array.prototype. includes method returns a Boolean value indicating whether an Array contains a given value, similar to the includes method of strings. ES2016 introduced this approach.

[1.2.3].includes(2)     // true
[1.2.3].includes(4)     // false
[1.2.NaN].includes(NaN) // true
Copy the code

The second argument to this method represents the starting position of the search, which defaults to 0. If the second argument is negative, it represents the reciprocal position, and if it is greater than the array length (for example, if the second argument is -4, but the array length is 3), it is reset to start at 0.

[1.2.3].includes(3.3);  // false
[1.2.3].includes(3, -1); // true
Copy the code

The indexOf method has two drawbacks. First, it is not semantic enough. It means to find the first occurrence position of the parameter value, so it is not intuitive enough to compare whether the value is not equal to -1. Second, it uses the strict equality operator (===) internally for judgment, which leads to misjudgment of NaN.

[NaN].indexOf(NaN)
// -1
Copy the code

Includes does not have this problem because it uses a different determination algorithm.

[NaN].includes(NaN)
// true
Copy the code

Flat (), flatMap()

The members of arrays are sometimes still arrays, array.prototype.flat () is used to “flatten” nested arrays into one-dimensional arrays. This method returns a new array with no effect on the original data.

Lat () by default “flattens” only one layer. If you want to “flatten” a nested array of multiple layers, you can write the argument to the flat() method as an integer representing the number of layers you want to flatten, which defaults to 1.

[1.2[3[4.5]]].flat()
// [1, 2, 3, [4, 5]]

[1.2[3[4.5]]].flat(2)
// [1, 2, 3, 4, 5]
Copy the code

In the code above, flat() takes 2 to “flatten” the two layers of nested arrays.

If you want to convert to a one-dimensional array regardless of the number of nesting levels, you can use the Infinity keyword as an argument.

[1[2[3]]].flat(Infinity)
/ / [1, 2, 3]
Copy the code

10. Empty space of array

A vacancy in an array means that there is no value at any point in the array. For example, the Array constructor returns arrays that are empty.

Array(3) / / /,,,
Copy the code

Note that a vacancy is not undefined, and a position equal to undefined is still valued. A vacancy is one that has no value, as the IN operator can indicate.

0 in [undefined.undefined.undefined] // true
0 in/,,,// false
Copy the code

ES6 explicitly converts empty space to undefined.

The array. from method converts the empty space of the Array to undefined, which means it doesn’t ignore the empty space.

Array.from(['a'.'b'])
// [ "a", undefined, "b" ]
Copy the code

Extended operators (…) It also changes the empty space to undefined.

[[...'a'.'b']]
// [ "a", undefined, "b" ]
Copy the code

CopyWithin () copies the empty space.

[,'a'.'b',,].copyWithin(2.0) // [,"a",,"a"]
Copy the code

Fill () treats the empty space as a normal array position.

new Array(3).fill('a') // ["a","a","a"]
Copy the code

for… The of loop also iterates over the empty space.

let arr = [, ,];
for (let i of arr) {
  console.log(1);
}
/ / 1
/ / 1
Copy the code

Entries (), keys(), values(), find() and findIndex() treat empty Spaces as undefined.

11.Array.prototype.sort() sort stability

const arr = [
  'peach'.'straw'.'apple'.'spork'
];

const stableSorting = (s1, s2) = > {
  if (s1[0] < s2[0]) return -1;
  return 1;
};

arr.sort(stableSorting)
// ["apple", "peach", "straw", "spork"]
Copy the code

The above code sorts the array ARR by the first letter

Insert sort, merge sort, bubble sort and so on are stable

Heap sort, quicksort, and so on are unstable

Extension of objects

1. Concise representation of properties

function f(x, y) {
  return {x, y};
}

const o = {
  method() {
    return "Hello!"; }};Copy the code

Setters and getters for properties are actually written this way.

const cart = {
  _wheels: 4,

  get wheels () {
    return this._wheels;
  },

  set wheels (value) {
    if (value < this._wheels) {
      throw new Error('Too small! ');
    }
    this._wheels = value; }}Copy the code

Brevity is also useful when printing objects.

let user = {
  name: 'test'
};

let foo = {
  bar: 'baz'
};

console.log(user, foo)
// {name: "test"} {bar: "baz"}
console.log({user, foo})
// {user: {name: "test"}, foo: {bar: "baz"}}
Copy the code

2. Attribute name expression

JavaScript defines attributes of objects in two ways.

/ / method
obj.foo = true;

/ / method 2
obj['a' + 'bc'] = 123;
Copy the code

ES6 allows literals to define objects using method two (expressions) as the object’s attribute name, that is, by placing the expression inside square brackets.

let propKey = 'foo';

let obj = {
  [propKey]: true['a' + 'bc'] :123
};
Copy the code

Expressions can also be used to define method names.

3. The name attribute of the method

const person = {
  sayName() {
    console.log('hello! ');
  },
  get foo() {},
  set foo(x) {}}; person.sayName.name// "sayName"
Copy the code

If an object’s methods use getters and setters, the name attribute is not on the method, but on the property description of the object’s GET and set properties. The return value is the method name preceded by get and set.

person.get.name // "get foo"
person.set.name // "set foo"
Copy the code

4. Enumerability and traversal of properties

The description of the Object. GetOwnPropertyDescriptor method can obtain the attribute Object

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
/ /}
Copy the code

An enumerable property that describes an object is called “enumerable.” If it is false, it means that some operations ignore the current property.

  • for... inLoop: Only the enumerable properties of the object itself and its inheritance are iterated over.
  • Object.keys(): returns the key names of all the enumerable properties of the object itself.
  • JSON.stringify(): Serializes only enumerable properties of the object itself.
  • Object.assign(): ignoreenumerableforfalseOnly enumerable properties of the object itself are copied.

In addition, ES6 states that all Class stereotype methods are non-enumerable.

Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false
Copy the code

Property traversal

ES6 has five methods for traversing an object’s properties.

(1) for… in

for… The in loop iterates over the object’s own and inherited enumerable properties (excluding the Symbol property).

(2) the Object. The keys (obj)

Keys returns an array containing the key names of all of the Object’s own (not inherited) enumerable properties (not including the Symbol property).

(3) Object. GetOwnPropertyNames (obj)

Object. GetOwnPropertyNames returns an array containing all attributes of the Object itself (excluding Symbol attribute, but cannot be enumerated attribute) of keys.

(4) the Object. GetOwnPropertySymbols (obj)

Object. GetOwnPropertySymbols returns an array containing all the Symbol attribute of the Object itself the key name.

(5) Reflect. OwnKeys (obj)

Reflect.ownKeys returns an array containing all of the object’s own (not inherited) key names, whether they are symbols or strings or enumerable.

All five methods follow the same sequence rules for traversal of attributes.

  • First, all numeric keys are iterated, sorted in ascending order.
  • Next, all the string keys are iterated in ascending order by the time they were added.
  • Finally, all Symbol keys are iterated in ascending order of time they were added.
Reflect.ownKeys({ [Symbol()] :0.b:0.10:0.2:0.a:0 })
// ['2', '10', 'b', 'a', Symbol()]
Copy the code

5. The super keyword

The this keyword always refers to the current object of the function. ES6 adds another similar keyword, super, to refer to the prototype object of the current object.

const proto = {
  foo: 'hello'
};

const obj = {
  foo: 'world'.find() {
    return super.foo; }};Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
Copy the code

6. Extension operators for objects

Deconstruction assignment

let{ x, y, ... z } = {x: 1.y: 2.a: 3.b: 4 };
x / / 1
y / / 2
z // { a: 3, b: 4 }
Copy the code

Note that a copy of a deconstructed assignment is a shallow copy, meaning that if the value of a key is a value of a compound type (array, object, function), the deconstructed assignment copies a reference to that value, not a copy of that value.

let obj = { a: { b: 1}};let { ...x } = obj;
obj.a.b = 2;
x.a.b / / 2
Copy the code

In addition, the destructive assignment of the extension operator cannot copy the attributes inherited from the prototype object.

let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
Copy the code

Extended operator

let z = { a: 3.b: 4 };
letn = { ... z }; n// { a: 3, b: 4 }

letfoo = { ... ['a'.'b'.'c']}; foo// {0: "a", 1: "b", 2: "c"}{... {},a: 1}
// { a: 1 }

// the same as {... Object(1)}
{..1.} / / {}

{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}

letaClone = { ... a };/ / is equivalent to
let aClone = Object.assign({}, a);
Copy the code

The extension operator can be used to merge two objects.

letab = { ... a, ... b };/ / is equivalent to
let ab = Object.assign({}, a, b);
Copy the code

7. Chain judgment operator? .

const firstName = (message
  && message.body
  && message.body.user
  && message.body.user.firstName) || 'default'; Simplified writing:constfirstName = message? .body? .user? .firstName ||'default';
Copy the code

8.Null judgment operator??

const headerText = response.settings.headerText || 'Hello, world! ';

const headerText = response.settings.headerText ?? 'Hello, world! ';
Copy the code

X. new methods for objects

1.Object.is()

It is used to compare whether two values are strictly equal, basically the same behavior as the strict comparison operator (===).

Object.is('foo'.'foo')
// true
Object.is({}, {})
// false
Copy the code

There are only two differences: +0 does not equal -0, and NaN equals itself.

+0= = = -0 //true
NaN= = =NaN // false

Object.is(+0, -0) // false
Object.is(NaN.NaN) // true
Copy the code

2.Object.assign()

The object.assign () method is used to merge objects. It copies all the enumerable properties of the source Object to the target Object.

Object.assign(target, source1, source2);
// object.assign () takes the first argument to the target Object and the rest to the source Object.
Copy the code

Note that if the target object has an attribute with the same name as the source object, or if multiple source objects have an attribute with the same name, the following attribute overrides the preceding one.

Because undefined and NULL cannot be converted to objects, they are reported as arguments. If undefined and null are not the first arguments, no error is reported.

Object.assign(undefined) / / an error
Object.assign(null) / / an error

// There is no error in the non-first argument
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
Copy the code

Only strings are incorporated into the target object (in the form of an array of characters), and both numeric and Boolean values are ignored. This is because only string wrapped objects produce enumerable properties.

Object.assign() copies only the source Object’s own properties (no inherited properties), and no non-enumerable properties (Enumerable: false).

Pay attention to the point

  1. Shallow copy

    The object.assign () method executes shallow copies, not deep copies.

  2. A replacement for an attribute of the same name

    For nested objects, once an attribute of the same name is encountered, object.assign () is handled by replacement rather than addition.

  3. Array handling

    Object.assign() can be used to work with arrays, but treats arrays as objects.

    Object.assign([1.2.3], [4.5])
    / / [4, 5, 3]
    Copy the code
  4. The processing of the value function

    Object.assign() can only be used to copy values. If the value to be copied is a value function, it will be evaluated and copied.

    const source = {
      get foo() { return 1}};const target = {};
    
    Object.assign(target, source)
    // { foo: 1 }
    Copy the code

    In the code above, the foo attribute of the source Object is an option. object.assign () does not copy this option. instead, it copies the value as it gets it.

Common use

The object.assign () method has many uses.

(1) Add attributes to the object

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y}); }}Copy the code

The above method adds the x and y attributes to the Object Object of the Point class using object.assign ()

(2) Add methods for objects

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2){...}.anotherMethod(){...}});Copy the code

(3) Clone objects

function clone(origin) {
  return Object.assign({}, origin);
}
Copy the code

4) Merge multiple objects

Merge multiple objects into an object.

const merge =
  (target, ... sources) = > Object.assign(target, ... sources);Copy the code

5) Specify default values for properties

options = Object.assign({}, DEFAULTS, options);
Copy the code

In the above code, the DEFAULTS object is the default value and the Options object is the user-supplied parameter.

3.Object.getOwnPropertyDescriptors()

Returns a description object for all of the specified object’s own attributes (non-inherited attributes).

const obj = {
  foo: 123.get bar() { return 'abc'}};Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
Copy the code

__4.proto__ attributes, Object.setProtoTypeof (), Object.getProtoTypeof ()

The __proto__ property (two underscores before and two underscores behind) is used to read or set the prototype of the current object.

Do not use this property for semantics or compatibility purposes, but instead use the following object.setPrototypeof () (write operation), Object.getPrototypeof () (read operation), object.create () (build operation).

__proto__ calls object.prototype.__proto__.

Object.defineProperty(Object.prototype, '__proto__', {
  get() {
    let _thisObj = Object(this);
    return Object.getPrototypeOf(_thisObj);
  },
  set(proto) {
    if (this= = =undefined || this= = =null) {
      throw new TypeError(a); }if(! isObject(this)) {
      return undefined;
    }
    if(! isObject(proto)) {return undefined;
    }
    let status = Reflect.setPrototypeOf(this, proto);
    if(! status) {throw new TypeError(a); }}});function isObject(value) {
  return Object(value) === value;
}
Copy the code

Object.setPrototypeOf()

The object. setPrototypeOf method does the same thing as __proto__, setting the prototype Object of an Object

/ / format
Object.setPrototypeOf(object, prototype)

/ / usage
const o = Object.setPrototypeOf({}, null);
Copy the code

Object.getPrototypeOf()

This method works with the Object.setPrototypeOf method and is used to read the prototype Object of an Object

Object.getPrototypeOf(obj);
Copy the code

5. object.keys (), object.values (), object.entries ()

let {keys, values, entries} = Object;
let obj = { a: 1.b: 2.c: 3 };

for (let key of keys(obj)) {
  console.log(key); // 'a', 'b', 'c'
}

for (let value of values(obj)) {
  console.log(value); / / 1, 2, 3
}

for (let [key, value] of entries(obj)) {
  console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Copy the code

6.Object.fromEntries()

The object.fromentries () method is the inverse of object.entries () and is used to turn an array of key-value pairs into objects.

Object.fromEntries([
  ['foo'.'bar'],
  ['baz'.42]])// { foo: "bar", baz: 42 }
Copy the code

The main purpose of this method is to restore the key-value pair’s data structure to an object, so it is particularly suitable for converting Map structures into objects.

const map = new Map().set('foo'.true).set('bar'.false);
Object.fromEntries(map)
// { foo: true, bar: false }
Copy the code

One use of this method is to turn the query string into an object in conjunction with the URLSearchParams object.

Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
Copy the code

Eleven, Symbol,

1. An overview of the

ES6 introduces a new primitive data type, Symbol, that represents unique values. It is the seventh data type in JavaScript, with undefined, NULL, Boolean, String, Number, and Object being the first six.

let s = Symbol(a);typeof s
// "symbol"
Copy the code

The Symbol function can take a string as an argument representing a description of the Symbol instance, mainly to make it easier to distinguish when displayed on the console or converted to a string.

let s1 = Symbol('foo')
s1 // Symbol(foo)
s1.toString() // "Symbol(foo)"
Copy the code

The argument to the Symbol function only represents a description of the current Symbol value, so the return value of the Symbol function with the same argument is not equal.

// No arguments
let s1 = Symbol(a);let s2 = Symbol(a); s1 === s2// false
// With parameters
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Copy the code

The Symbol value can be explicitly converted to a string.

let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
Copy the code

The Symbol value can also be converted to a Boolean value, but not to a value.

let sym = Symbol(a);Boolean(sym) // true
Copy the code

2.Symbol.prototype.description

const sym = Symbol('foo');

sym.description // "foo"
Copy the code

3. Symbol as attribute name

Since each Symbol value is not equal, this means that the Symbol value can be used as an identifier for the property name of the object, ensuring that no property with the same name will appear.

let mySymbol = Symbol(a);// The first way
let a = {};
a[mySymbol] = 'Hello! ';

// The second way
let a = {
  [mySymbol]: 'Hello! '
};

// The third way
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello! ' });

// All the above methods give the same result
a[mySymbol] // "Hello!"
Copy the code

The dot operator cannot be used when the Symbol value is the name of an object property.

const mySymbol = Symbol(a);const a = {};

a.mySymbol = 'Hello! ';
// a.mySymbol = 'Hello! ';

console.log(a.mySymbol); //Hello
console.log(a[mySymbol]); // undefined
console.log(a['mySymbol']); //Hello
Copy the code

When defining a property using a Symbol value, the Symbol value must be enclosed in square brackets.

letobj = { [s](arg) { ... }};Copy the code

4. Example: Eliminate magic strings

5. Traversal of attribute names

Symbol is the attribute name. When traversing the object, the attribute does not appear in the for… In, for… Of loop, will not be the Object. The keys (), Object, getOwnPropertyNames (), JSON. The stringify () returns.

Object. GetOwnPropertySymbols () method, which can get all the Symbol of specified Object attribute names

const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols
// [Symbol(a), Symbol(b)]
Copy the code

The reflect.ownkeys () method can return all types of key names, including regular and Symbol key names.

let obj = {
  [Symbol('my_key')]: 1.enum: 2.nonEnum: 3
};

Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
Copy the code

6. Symbol. The for (), Symbol keyFor ()

We want to reuse the same Symbol value, and the symbol.for () method does this. It takes a string as an argument and searches for a Symbol value with that argument as its name. If so, return the Symbol value, otherwise create a new Symbol with the name of the string and register it globally.

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true
Copy the code

Symbol. For () and Symbol() both generate a new Symbol. The difference is that the former will be registered in the global environment for search, while the latter will not. Symbol.for() does not return a new Symbol value each time it is called. Instead, it checks to see if the given key already exists and creates a new value if it does not. For example, if you call symbol. for(“cat”)30 times, the same Symbol will be returned each time, but calling Symbol(“cat”)30 times will return 30 different symbols.

The symbol.keyfor () method returns the key of a registered Symbol type value.

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
Copy the code

7. Example: The module’s Singleton pattern

The Singleton pattern refers to invoking a class that returns the same instance at all times.

For Node, a module file can be thought of as a class. How do I guarantee that the same instance will be returned each time I execute this module file?

It’s easy to imagine putting an instance into the top-level object, Global.

8. Built-in Symbol value

ES6 provides 11 built-in Symbol values that point to methods used internally in the language.

Symbol.hasInstance

When other objects use the instanceof operator to determine whether they are instances of the object, the operator on the left is determined to be an instance on the right.

Symbol.isConcatSpreadable

Object Symbol. IsConcatSpreadable attribute is a Boolean value, said that the object is used to Array. The prototype. The concat (), whether can be expanded.

let arr1 = ['c'.'d'];
['a'.'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined

let arr2 = ['c'.'d'];
arr2[Symbol.isConcatSpreadable] = false;
['a'.'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
Copy the code

Code above, the default behavior of the array is can expand, Symbol. IsConcatSpreadable default is undefined. This property is also expanded when it is true.

Array-like objects, by contrast, are not expanded by default. Its Symbol. IsConcatSpreadable attribute set to true, can be carried out.

let obj = {length: 2.0: 'c'.1: 'd'};
['a'.'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']

obj[Symbol.isConcatSpreadable] = true;
['a'.'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']
Copy the code

Symbol.species

Object’s symbol. species property, pointing to a constructor. This property is used when a derived object is created.

Set and Map data structures

1.set

The Set function can take an array (or some other data structure with an Iterable interface) as an argument for initialization.

const set = new Set([1.2.3.4.4]);
Copy the code

Properties and methods of a Set instance

Instances of the Set structure have the following properties.

  • Set.prototype.constructorThe: constructor is the defaultSetFunction.
  • Set.prototype.sizeReturns theSetThe total number of members of an instance.

The methods of a Set instance fall into two broad categories: operation methods (for manipulating data) and traversal methods (for traversing members). The following four operations are introduced.

  • Set.prototype.add(value): adds a value and returns the Set structure itself.
  • Set.prototype.delete(value): Deletes a value and returns a Boolean value indicating whether the deletion was successful.
  • Set.prototype.has(value): Returns a Boolean value indicating whether the value isSetA member of.
  • Set.prototype.clear(): Clears all members with no return value.

Traversal operation

(1)keys().values().entries()

An instance of a Set structure has four traversal methods that can be used to traverse members.

  • Set.prototype.keys(): returns a traverser for key names
  • Set.prototype.values(): returns a traverser for key values
  • Set.prototype.entries(): returns a traverser for key-value pairs
  • Set.prototype.forEach(): Iterates through each member using the callback function
let set = new Set(['red'.'green'.'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue
Copy the code

(2)forEach()

2.WeakSet

WeakSet structure is similar to Set, which is also a collection of non-repeating values. However, it differs from Set in two ways.

First, WeakSet members can only be objects, not other types of values.

Secondly, the objects in WeakSet are weak references, that is, garbage collection mechanism does not consider WeakSet’s reference to the object, that is to say, if other objects no longer reference the object, then garbage collection mechanism will automatically recover the memory occupied by the object, not considering the object still exists in WeakSet.

Due to the above feature, a WeakSet member is not suitable for reference because it will disappear at any time. The number of members is likely to be different before and after operation, and it is unpredictable when garbage collection mechanism runs, so ES6 stipulates that WeakSet cannot be traversed.

grammar

WeakSet is a constructor that creates a WeakSet data structure using the new command.

const ws = new WeakSet(a);Copy the code

WeakSet structure has the following three methods.

  • Weakset.prototype. add(value) : Adds a new member to the WeakSet instance.
  • Weakset.prototype. delete(value) : Clears the specified member of a WeakSet instance.
  • Weakset.prototype. has(value) : Returns a Boolean value indicating whether a value is in a WeakSet instance.

WeakSet has no size property, so there is no way to traverse its members.

3.Map

Instance properties and operation methods

(1) Size attribute

The size property returns the total number of Map structure members.

Prototype set(key, value)

The set method sets the key corresponding to the key name key to value and returns the entire Map structure. If the key already has a value, the key value is updated, otherwise the key is generated.

The set method returns the current Map object, so it can be chained.

let map = new Map()
  .set(1.'a')
  .set(2.'b')
  .set(3.'c');
Copy the code

(3) the Map. The prototype. The get (key)

The get method reads the corresponding key, and returns undefined if the key is not found.

4) the Map. The prototype. From the (key)

The HAS method returns a Boolean value indicating whether a key is in the current Map object.

const m = new Map(a); m.set('edition'.6);

m.has('edition')     // true
Copy the code

(5) the Map. The prototype. The delete (key)

The delete method deletes a key and returns true. If deletion fails, return false.

(6) the Map. The prototype. The clear ()

The clear method clears all members with no return value.

Traversal methods

The Map structure natively provides three traverser generating functions and one traversal method.

  • Map.prototype.keys(): returns a traverser for key names.
  • Map.prototype.values(): returns a traverser for key values.
  • Map.prototype.entries(): returns a traverser for all members.
  • Map.prototype.forEach(): Traverses all Map members.

Note in particular that the Map traversal order is the insertion order.

const map = new Map([['F'.'no'],
  ['T'.'yes']]);for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"
Copy the code

A faster way to convert a Map structure into an array structure is to use the extension operator (…). .

[...map.keys()]
/ / [1, 2, 3]

[...map.values()]
// ['one', 'two', 'three']

[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]

[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
Copy the code

Interconversion with other data structures

(1) Map is converted into an array

As mentioned earlier, the most convenient way to turn a Map into an array is to use the extension operator (…). .

(2) The array is converted to Map

The array is converted to a Map by passing it to the Map constructor.

new Map([[true.7],
  [{foo: 3},'abc']]])Copy the code

(3) Map is converted into an object

If all Map keys are strings, it can be converted to objects losslessly.

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes'.true)
  .set('no'.false);
strMapToObj(myMap)
// { yes: true, no: false }
Copy the code

If there is a non-string key name, it is converted to a string and used as the object’s key name.

4) Convert the object to Map

Objects can be turned into maps through Object.entries().

let obj = {"a":1."b":2};
let map = new Map(Object.entries(obj));
Copy the code

(5) Map is converted to JSON

There are two different cases of Map conversion to JSON. In one case, Map keys are all strings, and you can choose to convert to object JSON.

Alternatively, if the Map has a non-string key name, you can choose to convert it to an array JSON.

4.WeakMap

meaning

WeakMap structure is similar to Map structure and is also used to generate a set of key-value pairs. WeakMap differs from Map in two ways.

First, WeakMap only accepts objects as key names (except null) and does not accept other types of values as key names.

Second, the object to which the key name of WeakMap points is not included in the garbage collection mechanism. Once it is no longer needed, the key name object and the corresponding key value pair in WeakMap will disappear automatically, without manually deleting the reference.

The grammar of the WeakMap

There are two main differences between WeakMap and Map in API:

First, there is no traversal (that is, no keys(), values() and entries() methods) and no size attribute. Because there is no way to list all the key names, the existence of a particular key name is completely unpredictable and depends on whether the garbage collection mechanism is running. One moment the key name is available, the next moment the garbage collection mechanism is suddenly running, and the key name is gone, so in case of uncertainty, there is a general rule that the key name is not available.

Second, it cannot be cleared, that is, the clear method is not supported.

Therefore, WeakMap has only four methods available: get(), set(), has(), delete().