1. let const block-level scope
Deconstructive Assignment of Variables
1. Deconstructive Assignment of Variables
let [a, b, c] = [1, 2, 3];
Extract values from arrays and assign values to variables according to their corresponding locations
let [foo] = [];
let [bar, foo] = [1];
If the deconstruction is unsuccessful, the value of the variable is equal to undefined.
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
0 a,b=0,1
1 a,b=1,1
2 a,b=1,2
3 a,b=2,3
4 a,b=3,5
5 a,b=5,8
2. Default values
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
If an array member is null, the default value will not take effect because null is not strictly equal to undefined.
If the default value is an expression, the expression is evaluated lazily, that is, only when used.
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // Reference Error has not been declared yet
3. Deconstruction assignment of objects
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
There is an important difference between object deconstruction and array. The elements of an array are arranged in order, and the value of a variable is determined by its position; while the attributes of an object are not in order, the variables must have the same name as the attributes in order to get the correct value. Object deconstruction can also specify default values.
Different attribute names return undefined
Or write:
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
//So in fact
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
//Equivalent tolet { foo, bar} = { foo: "aaa", bar: "bbb" };
The latter is assigned, that is:
let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
Nesting can also be done
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p is a pattern, not a variable, so it won't be assigned.
If p is also assigned as a variable, it can be written as follows:
let { p, p: [x, { y }] } = obj;
p // ["Hello", {y: "World"}]
Another example
var node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
var { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}
nested assignment
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj // {prop:123}
arr // [true]
The default value takes effect only if the attribute value of the object is strictly equal to undefined.
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
If you want to use a declared variable for deconstruction assignment, you must be very careful.
let x;
{x} = {x: 1};// Wrong Writing
let x;
({x} = {x: 1});// Correct Writing
Object deconstruction assignment can easily assign methods of existing objects to a variable.
let { log, sin, cos } = Math;
The above code assigns the logarithmic, sinusoidal and cosine methods of Math objects to the corresponding variables, which makes it much easier to use.
Because arrays are special objects in nature, we can deconstruct the object attributes of arrays.
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
For example, we need to deconstruct the first and last values of the assignment array
var arr = [1,2,3,4,5,6,7];
var {0:first, [arr.length-1]: last} = arr;//herelastFor the left[]Put it in a bracket, it means to get it. arr[arr.length-1]
console.log(first);//output1
console.log(last);//output7
3. Structural assignment of strings
Strings can also deconstruct assignments. This is because at this point, the string is converted into an array-like object.
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
Objects like arrays have a length attribute, so you can also deconstruct and assign values to this attribute.
let {length : len} = 'hello';
len // 5
4. Deconstructive Assignment of Numbers and Boolean Values
When deconstructing assignment, if the right-hand side of the equal sign is a value and a Boolean value, it will first be converted to an object.
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
The wrapper objects for both values and Boolean values have toString attributes, so variables s can get values.
undefined and null cannot be converted to objects, so deconstructing them will cause errors.
5. Deconstruction and Assignment of Functional Parameters
Default values can also be used to deconstruct function parameters.
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
The following will give different results.
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
The above code specifies the default values for the parameters of the function move rather than for variables x and y, so you get a different result from the previous one.
undefined triggers the default value of the function parameter.
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
6. The problem of parentheses
Destruction assignment is convenient, but it is not easy to parse. For a compiler, it is impossible to know whether a formula is a pattern or an expression from the very beginning, but it must be resolved to (or not to) an equal sign.
The problem is what to do if parentheses appear in the schema. The rule of ES6 is that parentheses should not be used whenever it is possible to cause ambiguity in deconstruction.
However, this rule is actually not so easy to distinguish, and it is rather troublesome to deal with. Therefore, it is recommended that no parentheses be placed in the schema whenever possible.
Failure to use parentheses
(1) Variable declaration statement
// Full error reporting
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
(2) Functional parameters
function f([(z)]) { return z; }// Report errors
function f([z: (x)]) { return x; }// Report errors
(3) The pattern of assignment statement
// Full error reporting
({ p: a }) = { p: 42 };
([a]) = [5];
[({ p: a }), { x: c }] = [{}, {}];
Use of parentheses
Parentheses can be used in the non-schematic part of an assignment statement.
[(b)] = [3]; // Correct
({ p: (d) } = {}); // Correct
[(parseInt.prop)] = [3]; // Correct
7. Use
(1) Values of exchange variables
let x = 1;
let y = 2;
[x, y] = [y, x];
(2) Return multiple values from a function
Functions can only return one value, and if multiple values are to be returned, they can only be returned in arrays or objects. With deconstruction assignment, it is very convenient to extract these values.
function example() {
return [1, 2, 3];
}// Returns an array
let [a, b, c] = example();
function example() {
return {
foo: 1,
bar: 2
};
}// Return an object
let { foo, bar } = example();
(3) Definition of function parameters
Deconstruction assignment can easily correspond a set of parameters to variable names.
function f([x, y, z]) { ... }
f([1, 2, 3]);// A parameter is a set of ordered values
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});// A parameter is an unordered set of values
(4) Extracting JSON data
Deconstruction assignment is especially useful for extracting data from JSON objects.
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
(5) Default values of function parameters
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};
(6) Traversing Map Structure
Any object deployed with the Iterator interface can use for... Of loop traversal. Map structure supports Iterator interface naturally, and it is very convenient to obtain key names and key values with deconstruction assignment of variables.
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
for (let [key] of map) {
// Get the key name
}
for (let [,value] of map) {
// Get the key value
}
(7) Method of specifying input module
When loading modules, you often need to specify which methods to input. Deconstruction assignment makes the input statement very clear.
const { SourceMapConsumer, SourceNode } = require("source-map");
String Extension
1. Unicode representation of characters
JavaScript allows a character to be represented in the form of xxx, where xxxx represents the Unicode point of the character.
However, this representation is limited to characters between 0000 FFFFFF. Characters beyond this range must be expressed in two double bytes.
"\u0061"
// "a"
"\uD842\uDFB7"
// "��"
"\u20BB7"
// " 7"
The above code indicates that JavaScript can be understood as _ 20BB + 7 if it follows directly with values over 0xFFFF (such as 20BB7). Since 20BB is a non-printable character, only one space is displayed, followed by a 7.
ES6 improves this point by placing the code point in braces to correctly interpret the character.
"\u{20BB7}"
// "��"
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
The bracket representation is equivalent to the four-byte UTF-16 encoding.
With this representation, JavaScript has six ways to represent a character.
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
2.codePointAt()
Inside JavaScript, characters are stored in UTF-16 format, with each character fixed to 2 bytes. For characters that require four bytes of storage (characters with Unicode code code points greater than 0xFFFF), JavaScript considers them to be two characters.
var s = "��";
s.length // 2
s.charAt(0) // ''
s.charAt(1) // ''
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271
ES6 provides a codePointAt method that correctly handles four byte stored characters and returns a character's code point.
var s = '��a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
The parameter of the codePointAt method is the position of the character in the string (starting from 0). In the above code, JavaScript treats "" as three characters, and the codePointAt method correctly recognizes "" on the first character and returns its decimal point 134071 (that is, hexadecimal 20BB7). On the second character (that is, the last two bytes of "" and the third character "a", the result of the codePointAt method is the same as that of the charCodeAt method.
In summary, the codePointAt method correctly returns a 32-bit UTF-16 character code point. For those regular characters stored in two bytes, its return result is the same as that of the charCodeAt method.
The codePointAt method returns the decimal value of the code point. If you want the hexadecimal value, you can use the toString method to convert it.
var s = '��a';
s.codePointAt(0).toString(16) // "20bb7"
s.codePointAt(2).toString(16) // "61"
var s = '��a';
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61
The codePointAt method is the simplest way to test whether a character consists of two or four bytes.
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("��") // true
is32Bit("a") // false
3.String.fromCodePoint()
ES6 provides String.fromCodePoint method, which can recognize characters larger than 0xFFFF, and makes up for the shortcomings of String.fromCharCode method. In effect, it is just the opposite of the codePointAt method.
String.fromCodePoint(0x20BB7)
// "��"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
In the above code, if the String.fromCodePoint method has multiple parameters, they will be merged into a string and returned.
Note that the fromCodePoint method is defined on the String object, while the codePointAt method is defined on the instance object of the string.
4. Traverser interface for Strings
ES6 adds a traversal interface for strings (see Chapter Iterator for more details), so that strings can be used for ___________. of loop traversal.
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
In addition to traversing strings, the strongest advantage of this traversal is that it can identify code points larger than 0xFFFF FF, which can not be recognized by traditional for loop.
var text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "��"
In the code above, the string text has only one character, but the for loop assumes that it contains two characters (neither can be printed), and for... The of loop correctly recognizes this character.
5.normalize()
ES6 provides a normalize() method for string instances to unify the different representations of characters into the same form, which is called Unicode normalization.
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
The normalize method can accept a parameter to specify normalize, and the four optional values of the parameter are as follows.
NFC, the default parameter, denotes "Normalization Form Canonical Composition" and returns composite characters of multiple simple characters. The so-called "standard equivalence" refers to the visual and semantic equivalence.
NFD, which means "Normalization Form Canonical Decomposition", returns multiple simple characters decomposed by synthetic characters on the premise of standard equivalence.
NFKC, which means "Normalization Form Compatibility Composition", returns synthetic characters. The so-called "compatible equivalence" refers to the existence of semantic equivalence, but not visual equivalence, such as "gee" and "happiness". (This is just for example, normalize method can not recognize Chinese.)
NFKD, which means "Normalization Form Compatibility Decomposition", returns multiple simple characters decomposed by synthetic characters on the premise of compatibility equivalence.
'\u004F\u030C'.normalize('NFC').length // 1
'\u004F\u030C'.normalize('NFD').length // 2
The above code indicates that the NFC parameter returns the composition of characters and the NFD parameter returns the decomposition of characters.
However, normalize method can not recognize the synthesis of three or more characters at present. In this case, only regular expressions can be used to judge by the Unicode numbering interval.
6.includes(), startsWith(), endsWith()
Traditionally, JavaScript has only the indexOf method, which can be used to determine whether a string is contained in another string. ES6 provides three new approaches.
Include (): Returns a Boolean value indicating whether a parameter string has been found.
startsWith(): Returns a Boolean value indicating whether the parameter string is at the head of the source string.
endsWith(): Returns a Boolean value indicating whether the parameter string is at the end of the source string.
var s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
All three methods support the second parameter, which indicates where the search begins.
var s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
The code above shows that endsWith behaves differently from the other two methods when using the second parameter n. It is for the first n characters, while the other two methods are for the nth position until the end of the string.
7.repeat()
The repeat method returns a new string that repeats the original string n times.
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
If the parameter is a decimal, it will be integer downward (2.9 = 2), but if the parameter is a decimal between 0 and - 1, it will be equal to 0, because the integer operation will be performed first. The decimal number between 0 and - 1 is equal to - 0 when taken as an integer, and repeat is regarded as 0.
If the parameter of repeat is negative or Infinity, an error will be reported.
The parameter NaN is equal to 0.
If the parameter of repeat is a string, it is converted to a number first.
8.padStart(),padEnd()
ES2017 introduces the function of string completion length. If a string is not long enough, it will be filled in at the head or tail. padStart() is used for head repair and padEnd() for tail repair.
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
'abc'.padStart(10, '0123456789')// '0123456abc'
'x'.padStart(4) // ' x'
'x'.padEnd(4) // 'x '
In the code above, padStart and padEnd accept two parameters. The first parameter is used to specify the minimum length of the string, and the second parameter is used to complete the string.
If the length of the original string is equal to or greater than the specified minimum length, the original string is returned.
If the length of the complement string exceeds the specified minimum length, the complement string that exceeds the number of digits is truncated.
If the second parameter is omitted, the blank completion length is used by default.
The common use of padStart is to fill in a specified number of digits for a numerical value. The following code generates a 10-bit numeric string.
Another use is to Prompt string formats.
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
9. Template string
ES6 introduces template strings.
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
The template string is an enhanced version of the string, identified by a back quotation mark (`). It can be used as a regular string, as a definition of a multi-line string, or as an embedding variable in a string.
// Common string
`In JavaScript '\n' is a line-feed.`
// Multiline string
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// Embedded variables in strings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
The Template Strings in the above code are all represented by inverted quotation marks. If you need to use backquotes in template strings, you need to escape with backslashes before.
var greeting = `\`Yo\` World!`;
If a template string is used to represent a multi-line string, all spaces and indentations are retained in the output. such as
- There will be a line break in front of the label. If you don't want this newline, you can use the trim method to eliminate it.
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
Embedding variables in Template Strings requires that variable names be written in ${}.
function authorize(user, action) {
if (!user.hasPrivilege(action)) {
throw new Error(
// The traditional way of writing is
// 'User '
// + user.name
// + ' is not authorized to do '
// + action
// + '.'
`User ${user.name} is not authorized to do ${action}.`);
}
}
Within braces, any JavaScript expression can be placed, operations can be performed, and object attributes can be referenced, and functions can be invoked.
If the value in braces is not a string, it will be converted to a string according to general rules. For example, an object in braces will call the toString method of the object by default.
If the variables in the template string are not declared, an error will be reported.
Because JavaScript code is executed inside braces of template strings, if a string is inside braces, it will be output as it is.
Template strings can even be nested.
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
In the code above, another template string is embedded in the variables of the template string, using the following method.
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
// <table>
//
// <tr><td><Jane></td></tr>
// <tr><td>Bond</td></tr>
//
// <tr><td>Lars</td></tr>
// <tr><td><Croft></td></tr>
//
// </table>
If you need to refer to the template string itself and execute it as needed, you can write as follows.
// how to write
let str = 'return ' + '`Hello ${name}!`';
let func = new Function('name', str);
func('Jack') // "Hello Jack!"
// Writing II
let str = '(name) => `Hello ${name}!`';
let func = eval.call(null, str);
func('Jack') // "Hello Jack!"
10. Example: Template compilation
11. Label Template
12.String.raw()
ES6 also provides a raw method for native String objects.
String. ray method, often used as a template string processing function, returns a string whose slashes are escaped (that is, a slash is added before the slash), which corresponds to the template string after replacing variables.
String. ray will not do anything if the slash of the original string has been escaped.
String.raw`Hi\n${2+3}!`;
// "Hi\\n5!"
String.raw`Hi\u000A!`;
// 'Hi\\u000A!'
String.raw`Hi\\n`
// "Hi\\n"
The code for String. ray is basically the following.
String.raw = function (strings, ...values) {
var output = "";
for (var index = 0; index < values.length; index++) {
output += strings.raw[index] + values[index];
}
output += strings.raw[index]
return output;
}
13. Restrictions on Template Strings
As mentioned earlier, other languages can be embedded in the tag template. However, template strings are escaped by default, making it impossible to embed them in other languages.
For example, the LaTEX language can be embedded in the tag template.
-----—–2017/7/27