ES6语法总结

182 阅读8分钟

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 判断运算符

读取对象属性的时候,如果某个属性的值是nullundefined,有时候需要为它们指定默认值。

const headerText = response.settings.headerText || 'Hello, world!';
const animationDuration = response.settings.animationDuration || 300;
const showSplashScreen = response.settings.showSplashScreen || true;

开发者的原意是,只要属性的值为nullundefined,默认值就会生效,但是属性的值如果为空字符串或false0,默认值也会生效。 为了避免这种情况,ES2020 引入了一个新的 Null 判断运算符??。它的行为类似||,但是只有运算符左侧的值为nullundefined时,才会返回右侧的值。

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 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

12. Promise