ES6介绍:https://es6.ruanyifeng.com/#docs/intro
博客参考:https://www.cnblogs.com/sgs123/p/11481396.html
一 let和const
ES6 新增了let
命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。
let与var的区别
- let不存在变量提升
- 块级作用域:ES5 只有全局作用域和函数作用域,没有块级作用域(ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域)
let
不允许在相同作用域内,重复声明同一个变量
const常量
- const与let一样,唯一区别在于声明的常量不能被修改
函数声明
- ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明
- ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。函数声明语句的行为类似于
let
,在块级作用域之外不可引用。
二 变量的解构赋值
1 数组解构
es6支持“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值,如果解构不成功,变量的值就等于undefined
。
let [a, b, c] = [1, 2, 3] // a=1, b=2, c=3
let [a1, b1=2] = [1] // a1=1, b1=2 //指定默认值
let [d, [e], f] = [1, [2], 3] // 嵌套数组解构 d=1, e=2, f=3
let [g, ...h] = [1, 2, 3] // 数组拆分 g=1, h=[2, 3]
let [i,,j] = [1, 2, 3] // 不连续解构 i=1, j=3
let [k,l] = [1, 2, 3] // 不完全解构 k=1, l=2
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值
2 对象解构
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let {a, b} = {a:'aa', b:'bb'} //a='aa' b='bb'
//设置默认值
let {x, y = 5} = {x: 1}; //x= 1 y=5
//允许别名,a的值将失效
let {a:a1,b} = {a:'aa', b:'bb'} //a1='aa' b='bb'
let obj = {a:'aa', b: {c:'c'}}
let {a, b:{c}} = obj // 嵌套解构 a='aa' c='c'
(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心
//将一个已经声明的变量用于解构赋值
let x;
({x} = {x: 1});//将一个已经声明的变量用于解构赋值 x=1
{x} = {x: 1};// SyntaxError: syntax error
(2)解构赋值允许等号左边的模式之中,不放置任何变量名
({} = [true, false]);
({} = 'abc');
({} = []);
(3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;//first:1 last: 3
3 字符串的解构赋值
let [a, b, c] = 'hello' // a='h' b='e' c='l'
let {length : len} = 'hello'; //len: 5
4 数值和布尔值的解构赋值
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象
undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
5 函数参数的解构赋值
function say({name,age}){
console.log(name + '今年' + age)
}
say({name:'小明',age:18})
函数参数的解构也可以使用默认值。
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]
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]
-
扩展方法
三、字符串的扩展
1 加强了对 Unicode 的支持
加强了对 Unicode 的支持,允许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。(\u0000
~\uFFFF
之间)
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
2 JSON.stringify() 的改造
根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的JSON.stringify()
方法有可能返回不符合 UTF-8 标准的字符串。
如果遇到0xD800
到0xDFFF
之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
3 模板字符串
用反引号(`)标识,字符串中嵌入变量用${}
4 新增方法
ES5 提供String.fromCharCode()
方法,用于从 Unicode 码点返回对应字符,但是这个方法不能识别码点大于0xFFFF
的字符。
ES6 提供String.fromCodePoint()
方法,可以识别大于0xFFFF
的字符,弥补了String.fromCharCode()
方法的不足
String.fromCharCode(0x20BB7)//String.fromCharCode()不能识别大于0xFFFF的码点,所以0x20BB7就发生了溢出,最高位2被舍弃了,最后返回码点U+0BB7对应的字符
String.fromCodePoint(0x20BB7)// "𠮷"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'// true
//如果String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。
fromCodePoint
方法定义在String
对象上,而codePointAt
方法定义在字符串的实例对象上。
该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。如果原字符串的斜杠已经转义,那么String.raw()
会进行再次转义。
String.raw`Hi\n${2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"
String.raw`Hi\u000A!`;
// 实际返回 "Hi\\u000A!",显示的是转义后的结果 "Hi\u000A!
// `foo${1 + 2}bar`等同于
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
let s = '𠮷a';//“𠮷a”视为三个字符
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
//测试一个字符由两个字节还是由四个字节组成的最简单方法。
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("𠮷") // true
is32Bit("a") // false
将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()// true
let str = 'hello world'
//返回布尔值,表示是否找到了参数字符串
str.includes('r') //true
//返回布尔值,表示参数字符串是否在原字符串的头部
str.startsWith('hello') //true
//返回布尔值,表示参数字符串是否在原字符串的尾部
str.endsWith('d') //true
//repeat方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) // "xxx"
'na'.repeat(0) // ""
如果repeat
的参数是负数或者Infinity
,会报错。参数NaN
等同于 0,如果repeat
的参数是字符串,则会先转换成数字。
如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
如果省略第二个参数,默认使用空格补全长度。
对字符串实例新增了trimStart()
和trimEnd()
这两个方法。它们的行为与trim()
一致,trimStart()
消除字符串头部的空格,trimEnd()
消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
let str = ' hello world '
//消除首尾的空格
str.trim() //'hello world'
//消除字符串头部的空格
str.trimStart() //'hello world '
//消除尾部的空格
str.trimEnd() //' hello world'
matchAll()
方法返回一个正则表达式在当前字符串的所有匹配
四 正则的扩展
1 正则的扩展
ES5 中,RegExp
构造函数的参数有两种情况
//两种方式
var regex = new RegExp(/xyz/i);
var regex = new RegExp('xyz', 'i');
var regex = new RegExp(/xyz/, 'i'); //error
ES6 :如果RegExp
构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
new RegExp(/abc/ig, 'i').flags // "i"
2 字符串的正则方法
字符串对象共有 4 个方法,可以使用正则表达式:match()
、replace()
、search()
和split()
。
3 u 修饰符
对正则表达式添加了u
修饰符,含义为“Unicode 模式”,用来正确处理大于\uFFFF
的 Unicode 字符。
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
//ES5 不支持四个字节的 UTF-16 编码,会将其识别为两个字符,导致第二行代码结果为tru
一旦加上u
修饰符号,就会修改下面这些正则表达式的行为。
- 对于码点大于
0xFFFF
的 Unicode 字符,点字符不能识别,必须加上u
修饰符。 - ES6 新增了使用大括号表示 Unicode 字符,这种表示法在正则表达式中必须加上
u
修饰符,才能识别当中的大括号,否则会被解读为量词 - 使用
u
修饰符后,所有量词都会正确识别码点大于0xFFFF
的 Unicode 字符。 u
修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF
的 Unicode 字符。- 没有
u
修饰符的情况下,正则中没有定义的转义(如逗号的转义\,
)无效,而在u
模式会报错。
var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true
RegExp.prototy
//unicode属性,表示是否设置了u修饰符。
const r2 = /hello/u;
r2.unicode // true
4 y修饰符
ES6 还为正则表达式添加了y
修饰符,叫做“粘连”(sticky)修饰符。
y
修饰符的作用与g
修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g
修饰符只要剩余位置中存在匹配就可,而y
修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
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
//由于g修饰没有位置要求,所以第二次执行会返回结果,而y修饰符要求匹配必须从头部开始,所以返回null。
RegExp.prototype.sticky 属性
表示是否设置了y
修饰符。
var r = /hello\d/y;
r.sticky // true
5 RegExp.prototype.flags 属性
ES6 为正则表达式新增了flags
属性,会返回正则表达式的修饰符。
// ES5 的 source 属性
/abc/ig.source // "abc"
// ES6 的 flags 属性 返回正则表达式的修饰符
/abc/ig.flags // 'gi'
6 s 修饰符:dotAll 模式
正则表达式中,点(.
)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u
修饰符解决;另一个是行终止符(该字符表示一行的终结)
- U+000A 换行符(
\n
) - U+000D 回车符(
\r
) - U+2028 行分隔符(line separator)
- U+2029 段分隔符(paragraph separator)
dotAll
模式,即点(dot)代表一切字符。
re=/foo.bar/s
re.test('foo\nbar') // true
/foo.bar/.test('foo\nbar') // false
re.dotAll // true
正则表达式还引入了一个dotAll
属性,返回一个布尔值,表示该正则表达式是否处在dotAll
模式。