1. let 和 const 命令
1.1 let 命令
let 是ES6中新增的用于声明变量的关键字。
let 声明的变量只在所处于的块级有效 。使用let 关键字声明的变量才具有块级作用域(在一个{}内有效),使用var 声明的变量不具备块级作用域特性。
{
let a = 10;
var b = 1;
}
console.log(a);
console.log(b);
console.log(foo);
var foo = 2;
console.log(bar);
let bar = 2;
let 声明的变量具有暂时性死区特性。即在{}内不会再去访问外部的同名变量
var num = 10
if (true) {
console.log(num);
let num = 20;
}
let 不允许重复声明。let 不允许在相同作用域内,重复声明同一个变量。
function func() {
let a = 10;
var a = 1;
}
function func() {
let a = 10;
let a = 1;
}
function func(arg) {
let arg;
}
func()
function func(arg) {
{
let arg;
}
}
func()
1.2 块级作用域
let 实际上为 JavaScript 新增了块级作用域。{} 内为一个作用域.
- ES6 允许块级作用域的任意嵌套。
- 内层作用域可以定义外层作用域的同名变量。
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};
- 块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
(function () {
var tmp = ...;
...
}());
{
let tmp = ...;
...
}
- ES6 允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于
let ,在块级作用域之外不可引用。
1.3 const 命令
const 用于声明常量,常量就是值(内存地址)不能变化的量。
const PI = 3.14;
PI = 100;
const PI;
if (true) {
const a = 10;
}
console.log(a)
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
if (true) {
console.log(MAX);
const MAX = 5;
}
1.4 顶层对象属性
顶层对象,在浏览器环境指的是window 对象,在 Node 指的是global 对象。ES5 之中,顶层对象的属性与全局变量是等价的。
window.a = 1;
a
a = 2;
window.a
ES6规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
window.a
let b = 1;
window.b
2. 变量的解构赋值
2.1 数组的解构赋值
- “模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo
bar
baz
let [ , , third] = ["foo", "bar", "baz"];
third
let [x, , y] = [1, 2, 3];
x
y
let [head, ...tail] = [1, 2, 3, 4];
head
tail
let [x, y, ...z] = ['a'];
x
y
z
let [foo] = [];
let [bar, foo] = [1];
let [x, y] = [1, 2, 3];
x
y
let [a, [b], d] = [1, [2, 3], 4];
a
b
d
let [foo = true] = [];
foo
let [x, y = 'b'] = ['a'];
let [x, y = 'b'] = ['a', undefined];
2.2 对象的解构赋值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo
bar
let { baz } = { foo: 'aaa', bar: 'bbb' };
baz
let { log, sin, cos } = Math;
const { log } = console;
log('hello')
- 变量名与属性名不一致时,要给变量重命名与属性名一致
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f
l
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x
y
p
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
line
loc
start
var {x = 3} = {};
x
var {x, y = 5} = {x: 1};
x
y
var {x: y = 3} = {};
y
var {x: y = 3} = {x: 5};
y
var { message: msg = 'Something went wrong' } = {};
msg
let x;
{x} = {x: 1};
let x;
({x} = {x: 1});
- 解构赋值允许等号左边的模式之中,不放置任何变量名。
({} = [true, false]);
({} = 'abc');
({} = []);
- 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first
last
2.3 字符串的解构赋值
const [a, b, c, d, e] = 'hello';
a
b
c
d
e
let {length : len} = 'hello';
len
2.4 数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString
let {toString: s} = true;
s === Boolean.prototype.toString
let { prop: x } = undefined;
let { prop: y } = null;
2.5 函数参数的解构赋值
function add([x, y]){
return x + y;
}
add([1, 2]);
[[1, 2], [3, 4]].map(([a, b]) => a + b);
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8});
move({x: 3});
move({});
move();
2.6 圆括号问题
不可以使用圆括号的情况:
- 变量声明语句
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
- 函数参数(函数参数也属于变量声明)
function f([(z)]) { return z; }
function f([z,(x)]) { return x; }
- 赋值语句的模式
({ p: a }) = { p: 42 };
([a]) = [5];
可以使用圆括号的情况: 赋值语句的非模式部分,可以使用圆括号
[(b)] = [3];
({ p: (d) } = {});
[(parseInt.prop)] = [3];
2.7 用途
- 交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
- 从函数返回多个值
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
- 函数参数的定义
function f([x, y, z]) { ... }
f([1, 2, 3]);
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
- 提取 JSON数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
- 函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
} = {}) {
};
- 遍历Map结构
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
for (let [key] of map) {
}
for (let [,value] of map) {
}
- 输入模式的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
3. 字符串的扩展(不完整)
3.1 字符的 Unicode 表示法
这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
"\u0061"
"\uD842\uDFB7"
"\u20BB7"
"\u{20BB7}"
"\u{41}\u{42}\u{43}"
let hello = 123;
hell\u{6F}
'\u{1F680}' === '\uD83D\uDE80'
JavaScript 共有 6 种方法可以表示一个字符
'\z' === 'z'
'\172' === 'z'
'\x7A' === 'z'
'\u007A' === 'z'
'\u{7A}' === 'z'
3.2 字符串的遍历接口
for (let codePoint of 'foo') {
console.log(codePoint)
}
3.3 直接输入 U+2028 和 U+2029
JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。 U+005C:反斜杠(reverse solidus) U+000D:回车(carriage return) U+2028:行分隔符(line separator) U+2029:段分隔符(paragraph separator) U+000A:换行符(line feed)
console.log('\u4e2d')
3.4 JSON.stringfy() 的改造
为了确保返回的是合法的 UTF-8 字符,ES2019 改变了JSON.stringify()的行为。如果遇到0xD800到0xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。
JSON.stringify('\u{D834}')
JSON.stringify('\uDF06\uD834')
3.5 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
`In JavaScript '\n' is a line-feed.`
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
let greeting = `\`Yo\` World!`;
3.6 实例:模板编译
使用<%...%> 放置 JavaScript 代码,使用<%= ... %> 输出 JavaScript 表达式。
let template = `
<ul>
<% for(let i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %></li>
<% } %>
</ul>
`;
4. 字符串的新增方法
4.1 String.fromCodePoint()
String.fromCharCode() 方法,用于从 Unicode 码点返回对应字符,但是这个方法不能识别码点大于0xFFFF的字符。
String.fromCharCode(0x20BB7)
- ES6 提供了
String.fromCodePoint() 方法,可以识别大于0xFFFF的字符
String.fromCodePoint(0x20BB7)
4.2 String.raw()
ES6 还为原生的 String 对象,提供了一个raw()方法。该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。
String.raw`Hi\n${2+3}!`
String.raw`Hi\u000A!`;
String.raw`Hi\\n`
String.raw`Hi\\n` === "Hi\\\\n"
|