**以下内容均摘自ECMAScript 6 入门——阮一峰
一、let与const
1.let用于声明变量,let声明的变量只在代码块内有效‘{}’。
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
for循环设置循环变量是一个父作用域,循环体内部是一个子作用域
for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i); } // abc // abc // abc
2.不存在变量提升,声明的变量一定要在声明后使用,否则报错。(var声明的变量则会输出undefined)
3.暂时性死区,不存在变量提升所导致错误的另外一种说法。在区块内声明let变量之前,这些let变量都是不可用的。
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
4.let不允许在相同区块内,重复声明。
5.ES6的块级作用域,外层代码块不受内层代码块的影响。
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
6.const声明一个只读的常量,修改常量的值会报错,只声明不赋值会报错。
7.const只在块级作用域内有效,存在暂时性死区,不可重复声明。
8.const实际上保证的,是变量指向内存地址保存的数据不可改动,这点在简单数据类型和复合数据类型的行为上会有差异,因为复合数据类型保存的是数据指针。
const a = []; a.push('Hello'); // 可执行 a.length = 0; // 可执行 a = ['Dave']; // 报错
9.关于顶层对象,游览器中为window,Node中为global。全局环境中,this会返回顶层对象(严格模式返回undefined)。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
二、变量的解构赋值
1.数组的解构赋值(在数组中提取变量进行匹配)
let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" 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 // []
2.允许指定默认值(当提取成员===undefined,默认值才会生效)
let [foo = true] = []; foo // true let [x = 1] = [undefined]; x // 1 let [x = 1] = [null]; x // null
3.对象的解构赋值(变量名与属性名同名才能取到正确的值)
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
4.对象的解构赋值可以用于嵌套结构对象
let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p: [x, { y }] } = obj; x // "Hello" y // "World"
5.对象的解构也可以指定默认值
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"
6.字符串的解构赋值
const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
7.函数参数的解构赋值
function add([x, y]){ return x + y; } add([1, 2]); // 3 //为函数参数及参数的属性指定默认值 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]
8.不建议在解构赋值内加入圆括号,容易混淆模式与表达式。
三、字符串的扩展
1.includes() startsWith() endsWith()
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
这三个方法都支持第二个参数,表示开始搜索的位置。
2.repeat()
返回一个新字符串,表示将原字符串重复n次。参数如果是小数,会被取整。参数是负数或者Infinity,会报错。NaN等同于0.
3.padStart() padEnd()
padStart():头部补全 padEnd():尾部补全
'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 '
4.模板字符串
ES6引入模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量、表达式甚至函数。
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
//模板字符串甚至还能嵌套
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
5.标签模板
模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
alert`123` // 等同于 alert(123)
如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
let a = 5; let b = 10; tag`Hello ${ a + b } world ${ a * b }`; // 等同于 tag(['Hello ', ' world ', ''], 15, 50);
******“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。
6.String.raw()
String.raw方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串。
String.raw`Hi\n${2+3}!`;
// 返回 "Hi\\n5!"
String.raw`Hi\u000A!`;
// 返回 "Hi\\u000A!"
四、正则的拓展
1.字符串对象共有 4 个方法,可以使用正则表达式:match()、replace()、search()和split()。全都定义在RegExp对象上。
2.ES6 对正则表达式添加了u修饰符,含义为“Unicode 模式”。
//\uD83D\uDC2A是一个四个字节的 UTF-16 编码,代表一个字符。 /^\uD83D/u.test('\uD83D\uDC2A') // false /^\uD83D/.test('\uD83D\uDC2A') // true
//正则实例对象新增unicode属性,表示是否设置了u修饰符。 const r1 = /hello/; const r2 = /hello/u; r1.unicode // false r2.unicode // true
3.y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。
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
//ES6 的正则实例对象多了sticky属性,表示是否设置了y修饰符。 var r = /hello\d/y; r.sticky // true
4.flags属性,会返回正则表达式的修饰符。
// ES5 的 source 属性 // 返回正则表达式的正文 /abc/ig.source // "abc" // ES6 的 flags 属性 // 返回正则表达式的修饰符 /abc/ig.flags // 'gi'
五、数值的拓展
1.ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。
2.Number.isFinite(),Number.isNaN()
Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。如果参数类型不是数值,Number.isFinite一律返回false。
Number.isNaN()用来检查一个值是否为NaN。如果参数类型不是NaN,Number.isNaN一律返回false。
3.Number.parseInt(),Number.parseFloat()
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
4.Number.isInteger(),Number.isSafeInteger()
Number.isInteger()用来判断一个数值是否为整数。
ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。
5.Math对象的扩展
Math.trunc():用于去除一个数的小数部分,返回整数部分。
Math.sign():判断一个数到底是正数(+1)、负数(-1)、零(0或-0)、还是其他值(NaN)。
Math.cbrt():用于计算一个数的立方根。
Math.clz32():返回一个数的 32 位无符号整数形式有多少个前导 0。(对于小数,Math.clz32方法只考虑整数部分)
Math.imul():返回两个数以 32 位带符号整数形式相乘的结果。
Math.hypot():返回所有参数的平方和的平方根。
6.指数运算符
ES2016 新增了一个指数运算符(**)。
2 ** 2 // 4 2 ** 3 // 8 //右结合,而不是常见的左结合。 // 相当于 2 ** (3 ** 2) 2 ** 3 ** 2 // 512
