有空整理了ES6的常用语法,帮助自己经常巩固基础知识。
目录
ECMAScript 和 JavaScript 的关系
回顾历史,1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。
该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现
let和const命令
- let不存在变量提升
暂时性死锁:
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
123456var tmp = 123;if (true) {tmp = 'abc'; // ReferenceErrorlet tmp;}相同作用域内不允许重复生命一个变量。
块级作用域
let实际上为 JavaScript 新增了块级作用域。
12345678910function f1() {let n = 5;if (true) {let n = 10;}console.log(n); // 5}//上面的函数有两个代码块,都声明了变量n,运行后输出5//这表示外层代码块不受内层代码块的影响。//如果两次都使用var定义变量n,最后输出的值才是 10。const声明一个只读的常量。一旦声明,常量的值就不能改变。
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const声明的常量,也与let一样不可重复声明。
顶层对象说明
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令
和function
命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令
、const命令
、class
命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
global对象
ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。
- 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
- 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
- Node 里面,顶层对象是global,但其他环境都不支持。
同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。
- 全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
解构赋值
数组的解构赋值
从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
下面是一些使用嵌套数组进行解构的例子:
如果解构不成功,变量的值就等于undefined。
对于 Set 结构,也可以使用数组的解构赋值:
默认值
解构赋值允许指定默认值。
==注意,ES6 内部使用严格相等运算符(===
),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined
,默认值才会生效。==
上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值:
对象的解构
|
|
==对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。==
如果变量名与属性名不一致,必须写成下面这样:
也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
|
|
与数组一样,解构也可以用于嵌套结构的对象。
下面是嵌套赋值的例子:
对象的解构也可以指定默认值:
==默认值生效的条件是,对象的属性值严格等于(===)undefined
==
如果要将一个已经声明的变量用于解构赋值,必须非常小心:
上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。
由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构:
字符串的解构
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
==解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象.==
==由于undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错。==
函数参数的解构
|
|
|
|
函数参数的解构也可以使用默认值。
undefined就会触发函数参数的默认值。
圆括号问题
以下三种解构赋值不得使用圆括号:
- 变量声明语句 1234567// 全部报错let [(a)] = [1];let {x: (c)} = {};let ({x: c}) = {};let {(x: c)} = {};let {(x): c} = {};
上面 5 个语句都会报错,因为它们都是变量声明语句,模式不能使用圆括号。
函数参数
函数参数也属于变量声明,因此不能带有圆括号。
1234// 报错function f([(z)]) { return z; }// 报错function f([z,(x)]) { return x; }赋值语句的模式
123// 全部报错({ p: a }) = { p: 42 };([a]) = [5];
可以使用圆括号:
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;
其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;
第二行语句中,模式是p,而不是d;
第三行语句与第一行语句的性质一致。
字符串遍历器接口
ES6 为字符串添加了遍历器接口(详见《Iterator》一章),使得字符串可以被for…of循环遍历。
includes(), startsWith(), endsWith(), repeat(),padStart(),padEnd(),matchAll(),
传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了新方法:
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
- repeat(): 方法返回一个新字符串,表示将原字符串重复n次。
- padStart(): 如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全
- padEnd(): padEnd()用于尾部补全。
- matchAll(): matchAll方法返回一个正则表达式在当前字符串的所有匹配
|
|
这三个方法都支持第二个参数,表示开始搜索的位置。
上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
|
|
labelTemplate标签模版
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
|
|
“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。
同理:string.replace(/</g, '<').replace(/>/g, '>');
|
|
正则的扩展
在 ES5 中,RegExp构造函数的参数有两种情况。
第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag):
第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝:
但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错:
如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
上面代码中,原有正则对象的修饰符是ig,它会被第二个参数i覆盖。
String.prototype.matchAll
如果一个正则表达式在字符串里面有多个匹配,现在一般使用g修饰符或y修饰符,在循环里面逐一取出。
目前有一个提案,增加了String.prototype.matchAll方法,可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
|
|
数值的扩展
二进制和八进制表示法
ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b
(或0B
)和0o
(或0O
)表示。
如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法。
Number.parseInt(), Number.parseFloat()
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
Number.isInteger()
用来判断一个数值是否为整数。
注意,由于 JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger
可能会误判。
Math 对象的扩展
Math.trunc()
Math.trunc
方法用于去除一个数的小数部分,返回整数部分。
对于非数值,Math.trunc内部使用Number方法将其先转为数值。
对于空值和无法截取整数的值,返回NaN。
对于没有部署这个方法的环境,可以用下面的代码模拟。
Math.sign()
Math.sign
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值。
- 参数为正数,返回+1;
- 参数为负数,返回-1;
- 参数为 0,返回0;
- 参数为-0,返回-0;
- 其他值,返回NaN。12345Math.sign(-5) // -1Math.sign(5) // +1Math.sign(0) // +0Math.sign(-0) // -0Math.sign(NaN) // NaN
如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN。
https://www.tuicool.com/articles/zMbqmm6?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com
http://caibaojian.com/fe-interview.html