阮一峰大神ECMAScript 6 入门:https://es6.ruanyifeng.com/
大家要是看不惯这边的排版,可以去我的语雀看看,语雀真的绝
https://www.yuque.com/isremya/vqgp35
let 和 const 命令
- let声明的变量只在它所在的代码块有效。
- 变量
i
是var
命令声明的,在全局范围内都有效,所以全局只有一个变量i
。 - 变量
i
是let
声明的,当前的i
只在本轮循环有效,所以每一次循环的i
其实都是一个新的变量
- 另外,
for
循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
- ES6 明确规定,如果区块中存在
let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。即不存在变量提升。
- 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
let
不允许在相同作用域内,重复声明同一个变量。
function func(arg) {
let arg; //不能在函数内部重新声明参数。
}
func() // 报错
function func(arg) {
{
let arg;
}
}
func() // 不报错
- 允许在块级作用域内声明函数。
- 函数声明类似于
var
,即会提升到全局作用域或函数作用域的头部。 - 同时,函数声明还会提升到所在的块级作用域的头部。
// 块级作用域内部的函数声明语句,建议不要使用
{
let a = 'secret';
function f() {
return a;
}
}
// 块级作用域内部,优先使用函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
const
一旦声明变量,就必须立即初始化,不能留到以后赋值。
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
- ES6 一共有 6 种声明变量的方法。
var
命令和function
命令。let
和const
命令,import
命令和class
命令。
- ES6 一方面规定,为了保持兼容性,
var
命令和function
命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let
命令、const
命令、class
命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
- 全局环境中,
this
会返回顶层对象。但是,Node 模块和 ES6 模块中,this
返回的是当前模块。 - 函数里面的
this
,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this
会指向顶层对象。但是,严格模式下,这时this
会返回undefined
。
变量的解构赋值
- ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
- 如果解构不成功,变量的值就等于
undefined
。
- 数组的元素是按次序排列的,变量的取值由它的位置决定;
- 而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
//上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}
// 报错
let {foo: {bar}} = {baz: 'baz'};
//whywhywhy???
- 对象的解构也可以指定默认值。
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"
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
// 正确的写法
let x;
({x} = {x: 1});
//只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
- 字符串也可以解构赋值。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
- 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于
undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错。
- 函数也可以解构赋值。
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
- 不得使用圆括号的情况
- 变量声明语句
- 函数参数
- 赋值语句的模式
//以下三种模式全部报错
let [(a)] = [1];
let {x: (c)} = {};
function f([(z)]) { return z; }
({ p: a }) = { p: 42 };
([a]) = [5];
- 只有赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
- 变量的解构赋值用途
- 交换变量的值
- 从函数返回多个值
- 函数如果要返回多个值,只能将它们放在数组或对象里返回。
- 函数参数的定义
- 方便地将一组参数与变量名对应起来。
- 提取 JSON 数据
- 函数参数的默认值 review
- 遍历 Map 结构
- 任何部署了 Iterator 接口的对象,都可以用
for...of
循环遍历。 - Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
- 输入模块的指定方法 review
//交换变量
let x = 1;
let y = 2;
[x, y] = [y, x];
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
//提取 JSON 对象中的数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
//遍历 Map 结构
const 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) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
字符串的拓展
模板字符串
- 用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
- 如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
- 所有模板字符串的空格和换行,都是被保留的,可以使用
trim
方法消除它。 - 模板字符串中嵌入变量,需要将变量名写在
${}
之中。 - 模板字符串之中还能调用函数。
- 如果模板字符串中的变量没有声明,将报错。
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
let greeting = `\`Yo\` World!`;
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
实例:模板编译看不懂
标签模板 看不懂
字符串的新增方法
String.raw()
- 该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串
- 如果原字符串的斜杠已经转义,那么
String.raw()
会进行再次转义。
String.raw`Hi\n${2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"
//why why why?
// `foo${1 + 2}bar`
// 等同于
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
确定一个字符串是否包含在另一个字符串中
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat()
返回一个新字符串,表示将原字符串重复n
次
参数如果是小数,会被取整。
参数是负数或者Infinity
,会报错。
参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。
参数NaN
等同于 0。
参数是字符串,则会先转换成数字。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(2.9) // "nana"
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""
//why why why?
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"
padStart(),padEnd()
- 如果某个字符串不够指定长度,会在头部或尾部补全。
padStart()
用于头部补全,padEnd()
用于尾部补全。 - 如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
- 如果省略第二个参数,默认使用空格补全长度。
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'xxx'.padStart(2, 'ab') // 'xxx'
'x'.padStart(4) // ' x'
'x'.padEnd(4) // 'x '
trimStart(),trimEnd()
trimStart()
消除字符串头部的空格,trimEnd()
消除尾部的空格。- 它们返回的都是新字符串,不会修改原始字符串。
const s = ' abc ';
s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
matchAll()
- 返回一个正则表达式在当前字符串的所有匹配
来源:oschina
链接:https://my.oschina.net/u/4383725/blog/4467841