ES6语法总结
[参考文献](es6常用语法简记 - 掘金 (juejin.cn))
1. 声明方式
(1)let 声明
声明一个变量,有暂时性死区、无变量提升,有块级作用域。
let 声明的是一个变量,变量在声明且赋值后,能更改其赋的值。
(2)const 声明
声明一个常量,有暂时性死区、无变量提升,有块级作用域。
const声明一个常量,一旦声明必须立即初始化,一旦初始化之后,它的值不能再进行任何修改!
(3)var 声明
var声明一个变量,无暂时性死区,有变量提升,无块级作用域,只有函数作用域和全局作用域。
2. 变量的解构赋值
(1)交换变量的值
let x = 1
let y = 2
[x, y] = [y, x]
console.log(x, y) // 2, 1
(2)函数返回多个值
// 返回一个数组
function fun () {
return [1, 2, 3]
}
let [x, y, z] = fun()
console.log(x, y, z)
// 返回一个对象
function fun2 () {
return {
name: 'curry',
age: 18,
sex: 'female'
}
}
let {name, age, sex} = fun2()
console.log(name, age, sex) // curry 18 female
(3)函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
(4)提取JSON数据
let data = {
name: 'curry',
age: 18
}
let {name, age} = data
(5)函数参数的解构赋值
function add([x, y]) {
return x + y
}
add([1, 2])
(6)遍历map结构
for (let [key, value] of map) {
console.log(key + " is " + value)
}
(7)输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
3. 字符串扩展
(1)字符串的遍历器接口
for (let codePoint of 'foo') {
console.log(codePoint)
}
(2)模板字符串
let name = 'curry'
let str = `${name}是我的名字`
(3)includes()
返回布尔值,表示是否找到了该字符串
let str = 'curry is my name'
console.log(str.includes('curry')) // ture
PS:如果用indexOf查找,找到了就返回索引,否则返回-1
(4)startsWith()
返回布尔值,表示字符串是否在原字符串的头部
let str = 'curry is my name'
console.log(str.startsWith('curry')) // || str.indexOf('curry') == 0 true
(5)去除空格
.trim()
消除字符串两端的空格
.trimStart()
消除头部空格
.trimEnd()
消除尾部空格
replaceAll()
一次性替换所有匹配
str.replace(/ /g, '')
'aabbcc'.replaceAll('b', '_') == 'aabbcc'.replace(/b/g, '_') // true
4. 数值的拓展
(1)Number.isNaN()
用来检查一个值是否为
NaN。
5. 函数拓展
(1)函数参数的默认值
function fn(x, y = 1) {
console.log(x + y);
}
fn(10); // 11
(2)rest 参数
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort()
(3)严格模式
// 只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
// 报错
function doSomething(a, b = a) {
'use strict';
// code
}
// 报错
const doSomething = function ({a, b}) {
'use strict';
// code
};
// 报错
const doSomething = (...a) => {
'use strict';
// code
};
const obj = {
// 报错
doSomething({a, b}) {
'use strict';
// code
}
};
(4)箭头函数
const fn = x => x + 1
// 等价于
const fn = (x) => {
return x + 1
}
// 如果直接返回一个对象,外面的()不能省
let getItem = id => ({ id: id, name: 'curry'})
- 箭头函数没有自己的
this对象,内部的this就是定义时上层作用域中的this。 - 不可以当作构造函数,也就是说,不可以对箭头函数使用
new命令,否则会抛出一个错误。 - 不可以使用
arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。 - 不可以使用
yield命令,因此箭头函数不能用作 Generator 函数。
6. 数组的扩展
(1)扩展运算符
// 复制数组
const a1 = [1, 2];
const a2 = [...a1]; // [1, 2];
// 注:返回的是一个新数组
// 合并数组
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const newArr = [...arr1, ...arr2]; //['a', 'b', 'c'];
// a3 和 a4 是用两种不同方法合并而成的新数组,但是它们的成员都是对原数组成员的引用,这就是浅拷贝。如果修改了引用指向的值,会同步反映到新数组。
const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];
const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];
a3[0] === a1[0] // true
a4[0] === a1[0] // true
// 将字符串转为数组
[...'hello'] // ["h", "e", "l", "l", "o"]
// 数组去重
[...new Set(arr)] // 如果是对象就不适用
(2)Array.from()
用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
(3)Array.of()
用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
(4)flat()
扁平化数组
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
(5)filter
创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。(也就是过滤出满足当前条件的所有元素)
(6)数组排序+去重
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current) => {
if(init.length === 0 || init[init.length-1] !== current) {
init.push(current);
}
return init;
}, []);
console.log(result); //[1,2,3,4,5]
7. 对象的扩展
(1)属性的简洁表示法(对象解构赋值)
const name = "张三";
const id = 1;
const obj = {
name: name,
id: id
};
// 如果对象的属性名和变量名一致,可简写成:
const obj = {name,id};
obj // {name: "张三", id: 1}
const obj = {
a: {
b: {
c: 123
}
}
}
console.log(obj.a.b.c)
const { a: { b: { c } } } = obj
console.log(c) //等于obj.a.b.c
(2)扩展运算符
- 取出参数对象的所有可遍历属性,拷贝到当前对象之中
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
- 如果扩展运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象。
{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
- 合并两个对象(此处用的较多)
let params = {
...this.pageObj, // 分页对象
...this.searchForm // 搜索框表单对象
}
- 如果想完整克隆一个对象,还拷贝对象原型的属性,可采用以下方法。
// 写法一
const clone1 = {
__proto__: Object.getPrototypeOf(obj),
...obj
};
// 写法二
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
);
// 写法三
const clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)
(3)Object.assign()
- 用于对象的合并
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 浅拷贝
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
// `Object.assign()`拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。
8. 运算符扩展
(1)指数运算符(\**)
2 ** 2 // 4
2 ** 3 // 8
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
(2)链判断运算符
如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。比如,读取
message.body.user.firstName这个属性,安全的写法是写成下面这样。
// 错误的写法
const firstName = message.body.user.firstName || 'default';
// 正确的写法
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
// 链判断运算符简写
const firstName = message?.body?.user?.firstName || 'default';
- 短路机制
本质上,?.运算符相当于一种短路机制,只要不满足条件,就不再往下执行。
a?.[++x]
// 等同于
a == null ? undefined : a[++x]
(3)Null 判断运算符
读取对象属性的时候,如果某个属性的值是
null或undefined,有时候需要为它们指定默认值。
const headerText = response.settings.headerText || 'Hello, world!';
const animationDuration = response.settings.animationDuration || 300;
const showSplashScreen = response.settings.showSplashScreen || true;
开发者的原意是,只要属性的值为
null或undefined,默认值就会生效,但是属性的值如果为空字符串或false或0,默认值也会生效。 为了避免这种情况,ES2020 引入了一个新的 Null 判断运算符??。它的行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值。
const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;
9. Symbol
10. Set 和 Map 数据结构
(1)Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
set
1. add方法为其添加成员;
2. has查看是否有该值;
3. delete删除某个值,返回布尔值
4. clear清除所有成员
5. size返回Set实例的成员总数
(2)Map
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
map
1. has查看是否有该值
2. get获取属性
3. set设置属性
4. delete删除属性
5. size属性返回 Map 结构的成员总数。
6. clear方法清除所有成员,没有返回值。
(3)Set和Map的遍历
//set -----------------------------------
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
for (let item of set.values()) {
console.log(item);
}
for (let item of set.entries()) {
console.log(item);
}
// map-----------------------------------
const map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
11. Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。