ES6语法

202 阅读10分钟

一. ES6 语法

1.1 let/const关键字

  • let声明的变量不存在预解析(变量提升)
  • let变量不允许重复声明(在同一个作用域内)
  • 块级作用域
  • 不影响作用域链

  • const声明的常量必须初始化
  • 不允许重新赋值
  • 块级作用域
  • 当使用常量 const 声明时,请使用大写变量

1.2 变量的解构赋值

​ 允许按照一定模式从数组和对象中提取值,对变量进行赋值(解构赋值)。

// 数组的解构赋值
let [a, b, c] = [123];
console.log(a, b, c);
let [d = 1, e, f] = [, 123];
console.log(d,e,f);

// 对象的解构赋值

let {foo, bar} = {foo'hello', bar : 'h1'};

// 对象属性别名

let { foo: abc, bar } = { foo'hello'bar'h1' };
console.log(abc, bar);

// 字符串的解构赋值

let [a, b, c, d, e, length] = "hello";
console.log(a, b, c, d, e);
console.log(length);
console.log("hello".length);

1.3 字符串相关扩展

  • includes() 判断字符串中是否包含指定的字串
  • startWith() 判断字符串是否以特定的字串开始
  • endWidth() 判断字符串是否以特定的字串结束
1.31 模板字符串
  • 符号使用``
  • 内容中可以直接出现换行符
  • 变量拼接 ${变量}

1.4 简化对象写法

let name = "zs",
  age = 18,
  sex = "男";
let obj = {
  name,
  age,
  sex,
  test() {
    console.log("hello");
  },
};
console.log(obj);

1.5 箭头函数

// 箭头函数的注意事项:
// 1、箭头函数中this取决于函数的定义,而不是调用
 function foo(){
//     使用call调用foo时,这里的this其实就是call的第一个参数
     console.log(this);
     setTimeout(()=>{
         console.log(this.num);
     },100);
 }
 foo.call({num:1});
// ----------------------------------
// 2、箭头函数不能作为构造实例化对象,不可以new
 let foo = () => { this.num = 123;};
 new foo();
// ------------------------------------
// 3、箭头函数不可以使用arguments获取参数列表,可以使用rest参数代替
 let foo = (a,b) => {
      console.log(a,b);
     console.log(arguments);//这种方式获取不到实参列表
 }
 foo(123,456);
let foo = (...param) => {
  console.log(param);
};
foo(123456);

1.6 函数扩展

1.61 参数默认值
function sum(a = 1, b = 2) {
	console.log(a + b);
}

sum();
sum(4, 4);

1.62 参数的解构赋值
function sum({ name = "zs", age = 18 } = {}) {
	console.log(name, age);
}

sum();
sum({ name: "ls", age: 20 });
1.62 rest 参数(剩余参数)
function sum(a, b, ...param) {
	console.log(a);
	console.log(b);
	console.log(param);
}

sum(1, 2, 3, 4, 5, 6, 7);

1.63 ... 扩展运算符
function sum(a, b, c, d, e, f, g) {
	console.log(a + b + c + d + e + f + g);
}

let arr = ["1", 2, 3, 4, 5, 6, 7];
sum(...arr);

// 合并数组
let arr1 = [1, 2, 3];
let arr2 = [6, 6, 6];
let arr3 = [...arr1, ...arr2];
console.log(arr3);

1.7 Symbol数据类型

  • Symbol值唯一,解决命名冲突的问题

  • Symbol值不能与其他数据进行运算

  • Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

    Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
    Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
    
    Symbol.for("bar") === Symbol.for("bar"); // true
    Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol
    
    let sym = Symbol.for("mario");
    sym.toString();
    
    // "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串
    
    // 添加Symbol类型的属性
    let obj = {
          num: Symbol(),
    
    [Symbol('say')]: function(){
        
              console.log("说话")
          }
      }
      console.log(obj)
    
1.71 Symbol内置值
内置值作用
Symbol.hasInstance其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable布尔值,对象用于Array.prototype.concat()时,是否可以展开。
Symbol.iterator对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器
......

1.8 迭代器

迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作。(自定义遍历数据)

1)for...of遍历

2)原生具备iterator接口的数据(可用for of 遍历):Array,Arguments,Set,Map,String,TypedArray,NodeList

3)对象next()方法,返回一个包含value和done属性的对象

    // 需求 for of 遍历 每次返回结果是数组成员
    const obj = {
      name: '西游记',
      stu: ['swk','ts','zbj','ss'],
      [Symbol.iterator]() {
        // 索引变量
        let index = 0
        let _this = this
        return {
          next() {
            if (index < _this.stu.length) {
              const result = {
                value: _this.stu[index],
                done: false
              }
              // 下标自增
              index++
              // 返回结果
              return result
            } else {
              return {value: undefined,done: true}
            }
          }
        }
      }
    }

    for (let v of obj) {
      console.log(v)
    }

1.9 生成器

​ 生成器:一个特殊的函数,异步编程的一种解决方案

  function* gen(arg) {
    console.log(arg)
    console.log(1)
    // yield 分隔符
    yield '眼睛'
    console.log(2)
    yield '鼻子'
    console.log(3)
    yield '耳朵'
  }
  // 执行获取迭代器对象
  let iterator = gen('AAA')
  // iterator.next() ---1
  // iterator.next() ---1 2
  // iterator.next() ---1 2 3
  // next 方法可以传入实参,参数作为上一个yield的返回结果
  // iterator.next('BBB')
  // 遍历
  for (let v of gen()) {
    console.log(v)
  }

实例:

    // 模拟获取 用户数据 订单数据 商品数据
    function getUser() {
      setTimeout(function () {
        let data = "用户数据"
        // 调用 next 方法,并将数据传入
        iterator.next(data)
      }, 1000)
    }

    function getOrder() {
      setTimeout(function () {
        let data = "订单数据"
        iterator.next(data)
      }, 1000)
    }
    
    function getGoods() {
      setTimeout(function () {
        let data = "商品数据"
        iterator.next(data)
      }, 1000)
    }
    
    function* gen() {
      let users = yield getUser()
      console.log(users)
      let order = yield getOrder()
      console.log(order)
      let goods = yield getGoods()
      console.log(goods)
    }
    
    // 调用生成器函数
    let iterator = gen();
    iterator.next()

2.0 Promise

​ 语法上Promise是一个构造函数,内部封装异步操作并可以获取其成功或失败的结果,异步编程的一种解决方案,用来解决回调地狱(在回调函数外面处理接收的数据)。

Promise三种状态:

  1. pending[等待]等待状态
  2. fulfilled[满足]满足状态
  3. rejected[拒绝]拒绝状态

当promise状态发生改变,就会触发then()里的响应函数处理后续步骤。

Promise状态改变只有:

  1. 从pending变为fulfilled
  2. 从pending变为rejected

promise状态一经改变,不会再变。

const p = new Promise((resolve, reject) => {
	setTimeout(function () {
		resolve("数据!"); // pending --> fulfilled
		reject("error!"); // pending --> rejected
	}, 1000);
});

// then方法和catch方法返回的结果都是promise对象,对象状态由回调函数的执行结果决定(PromiseStatus,PromiseValue)
// 链式调用

p.then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
})

p.then(
	res => {
		console.log(res);
	},
	err => {
		console.log(err);
	}
);

2.1 Set(集合)

​ 新的数据结构Set(集合),类似于数组,但成员的值都是唯一的,集合实现了interator接口,所以可以使用【扩展运算符】和【for...of...】进行遍历,集合的属性和方法:

let s = new Set(["zs", "ls", "zs", "ww"]);
// 自动去重
console.log(s);
// 元素个数
console.log(s.size);
// 增加元素
s.add("jj");
console.log(s);
// 删除元素
s.delete("ls");
console.log(s);
// 检测集合中是否包含某个元素,返回boolean值
console.log(s.has("zs"));
// 清空
s.clear();
console.log(s);

实践:

let arr = [1, 2, 3, 4, 4, 5, 5, 6];

// 1.数组去重
let result = [...new Set(arr)];
console.log(result);

// 2.交集

let arr2 = [4, 5, 3, 6, 6];
let result2 = [...new Set(arr)].filter((item) => new Set(arr2).has(item));
console.log(result2);

// 3.并集

let arr3 = [10, 1, 2, 9, 9];
let result3 = [...new Set([...arr, ...arr3])];
console.log(result3);

// 4.差集

let arr4 = [4, 5, 3, 9, 10];

let diff = [...new Set(arr)].filter((item) => !new Set(arr2).has(item));
console.log(diff);

2.2 Map

​ 类似与对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map实现了interator接口,所以可以使用【扩展运算符】和【for...of...】进行遍历,Map的属性和方法:

let m = new Map();
console.log(m);

// 添加元素
m.set("name", "zs");
m.set("age", 18);
m.set("change", function () {
	console.log("hello world!");
});
console.log(m);

//  获取元素个数size

console.log(m.size);

// 删除元素

m.delete("name");
console.log(m);

// 获取元素值

console.log(m.get("age"));

// 遍历

for (let v of m) {
	// 数组 键-->值
	console.log(v);
}

// 清空

// m.clear();

2.3 class类

class Student {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}

	say() {
		console.log("hello world");
	}
}

let iphone = new Student("zs", 18);
console.log(iphone);
iphone.say();

// 实例对象不能获取构造函数对象的静态属性

class Student {
	// 静态属性
	static name = "zs";
	static say() {
		console.log(hello);
	}
}
let ww = new Student();
console.log(ww.name);
console.log(ww.say);

2.31 继承
// ES5构造函数继承

function Person(name, age) {
	this.name = name;
	this.age = age;
}

Person.prototype.say = function () {
	console.log(this.name + "---" + this.age);
};

function Student(name, age, sex) {
	Person.call(this, name, age);
	this.sex = sex;
}

// 设置子级构造函数的原型
Student.prototype = new Person();
Student.prototype.constructor = Student;

// 声明学生的方法

Student.prototype.study = function () {
	console.log("学习使我快乐");
};

const zs = new Student("zs", 18, "man");
console.log(zs);
console.log(zs.__proto__);

// ---------------------------------------------------------------------

// ES6 继承

class Person {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	say() {
		console.log("hello");
	}
}

class Student extends Person {
	constructor(name, age, sex) {
		// super方法可以调用父级的constructor方法
		// 	Person.call(this, name, age);
		super(name, age);
		this.sex = sex;
	}
    // 子类对父类方法的重写
    say(){
        console.log("world");
    }
    
	study() {
		console.log("学习使我快乐");
	}
}
const zs = new Student("zs", 18, "man");
console.log(zs);

2.32 get和set
    class Person {
      get say() {
        console.log("hello");
        return "world";
      }

      // set 一定要有参数
      set say(newVal) {
        console.log("hello");
      }
    }

    const zs = new Person();
    // console.log(zs.say);

    zs.say = "f"; // hello

2.4 数值扩展

2.4.1 二进制和八进制

ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

2.4.2 Number方法
  1. Number.isFinite() 用来检查一个数值是否为有限的
  2. Number.isNaN() 用来检查一个值是否为 NaN
  3. Number.isInteger() 用来判断一个数值是否为整数
  4. Number.parseInt() 与 Number.parseFloat() :ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
  5. Number.isInteger() 判断一个数是否为整数
  6. Math.trunc() 将数字的小数部分抹掉
  7. Math.sign() 判断一个数到底是正数1 负数-1 还是零0

2.5 对象方法的扩展

  1. Object.is() 判断两个值是否完全相等

    console.log(Object.is(NaN, NaN)); // true
    console.log(NaN === NaN); //false
    
  2. Object.assign 对象的合并

    const a = {
    	name: "zs",
    	age: 18,
    };
    const b = {
    	name: "ls",
    	sex: "man",
    };
    // 同名属性,取第二个参数对象的
    console.log(Object.assign(a, b));
    
    
  3. Object.setPrototypeOf 设置对象原型,Object.getPrototypeOf 设置对象原型

    const a = {
    	name: "zs",
    	age: 18,
    };
    const b = {
    	sex: "man",
    };
    
    Object.setPrototypeOf(a, b);
    console.log(Object.getPrototypeOf(a));
    console.log(a);
    

2.6 模块化

模块化是一种思想, 是将大工程拆成小的模块分治的思想.

2.6.1 模块化规范产品

ES6之前的模块化规范有:

  1. CommonJS => NodeJS
  2. AMD => requireJS
  3. CMD => seaJS
2.6.2 ES6模块化

模块功能主要由两个命令构成:export 和 import。

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其他模块提供的功能
<script type="module" src="path"></script>

// --------------- 导出方式---------------

// 分别导出
export let name = "zs";

export function say() {
	console.log("hello");
}

// 统一导出
let name = "zs";

function say() {
	console.log("hello");
}

export { name, say };

// 默认导出
export default {
	name: "zs",
	say() {
		console.log("hello");
	},
};

// ---------------导入方式---------------

// 1.通用的导入方式
import * as m from "path";

// 2.解构赋值形式
import { name, say } from "path";

// 使用别名,防止命名相同
import { name as names, say } from "path";
import { default as m } from "path";

// 3.简便形式 针对默认导出
import m from "path";

二. ES7 新特性

// includes
const obj = ['zs','ls'];
console.log(obj.includes('zs')); // true

// **
console.log(2 ** 10); // 2的10次方1021
console.log(Math.pow(2,10));

三. ES8 新特性

1.1 async 和 awit

async 和 await 两种语法结合可以让异步代码像同步代码一样

1.11 async 函数
  1. async 函数的返回值为 promise对象
  2. promise 对象的结果由 async 函数执行的返回值决定
1.12 await 表达式
  1. await 必须写在 async 函数中

  2. await 表达式右侧值一般为 promise 对象

  3. await 返回的是 promise 成功的值

  4. await 的 promise 失败了,就会抛出异常,需要通过 try...catch 捕获处理

    const p = new Promise((resolve, reject) => {
    	// resolve("zs");
    	reject("error!");
    });
    
    // await 函数要放在 async 函数中
    async function main() {
    	try {
    		let result = await p;
    		console.log(result);
    	} catch (error) {
    		console.log(error);
    	}
    }
    
    main();
    
    

    1.2 对象方法扩展

    1.219 Object.values和Object.entries和Object.getOwnPropertyDescriptors
    const obj = {
    	name: "zs",
    	age: 18,
    	tx: ["ls", "ww", "ll"],
    };
    
    // 获取对象的键 [ 'name', 'age', 'tx' ]
    console.log(Object.keys(obj));
    
    // 获取对象的值 ["zs", 18, ["ls", "ww", "ll"]];
    console.log(Object.values(obj));
    
    // 获取对象的键值对 [ [ 'name', 'zs' ], [ 'age', 18 ], [ 'tx', [ 'ls', 'ww', 'll' ] ] ]
    console.log(Object.entries(obj));
    
    // 获取对象属性的描述对象
    console.log(Object.getOwnPropertyDescriptors(obj));
    
    // {
    //   name: { value: 'zs', writable: true, enumerable: true, configurable: true },
    //   age: { value: 18, writable: true, enumerable: true, configurable: true },
    //   tx: {
    //     value: [ 'ls', 'ww', 'll' ],
    //     writable: true,
    //     enumerable: true,
    //     configurable: true
    //   }
    // }
    
    

四. ES9 新特性

1.11 对象的 rest 参数和扩展运算符

ES9中为对象提供像数组一样的 rest 参数和扩展运算符

1.12 正则扩展

  1. 正则扩展-命名捕获分组

    let str = '<a href="http://www.baidu.com">百度</a>';
    
    // 正则表达式
    const reg = /<a href="(.*)">(.*)<\/a>/;
    
    const result = reg.exec(str);
    
    // [
    // 	'<a href="http://www.baidu.com">百度</a>',
    // 	"http://www.baidu.com",
    // 	"百度",
    // 	(index: 0),
    // 	(input: '<a href="http://www.baidu.com">百度</a>'),
    // 	(groups: undefined),
    // ]
    console.log(result);
    
    const reg2 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
    
    const result2 = reg2.exec(str);
    
    // [
    //   '<a href="http://www.baidu.com">百度</a>',
    //   'http://www.baidu.com',
    //   '百度',
    //   index: 0,
    //   input: '<a href="http://www.baidu.com">百度</a>',
    //   groups: [Object: null prototype] { url: 'http://www.baidu.com', text: '百度' }
    // ]
    console.log(result2);
    console.log(result2.groups);
    
    
  2. 正则扩展-反向断言

    let str = "JS123你知道444啦";
    
    const reg = /\d+(?=啦)/;
    
    const res = reg.exec(str);
    
    // ["444", (index: 8), (input: "JS123你知道444啦"), (groups: undefined)];
    console.log(res);
    
    const reg2 = /(?<=S)\d+/;
    
    const res2 = reg2.exec(str);
    
    // ["123", (index: 2), (input: "JS123你知道444啦"), (groups: undefined)];
    console.log(res2);
    
    
  3. 正则扩展-dotAll模式

    let str = `
      <ul>
        <li>
          <a>肖生克的救赎</a>
          <p>上映时间:1994-09-10</p>
        </li>
        <li>
          <a>阿甘正传</a>
          <p>上映时间:1994-07-06</p>
        </li>
      </ul>`;
    // 声明正则 ? 非贪婪模式
    // const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
    
    // /.*/  s模式修正符(.可以匹配任意字符)   g全局匹配
    const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
    
    let res;
    let data = [];
    while ((result = reg.exec(str))) {
    	data.push({ title: result[1], time: result[2] });
    }
    console.log(data);
    // const res = reg.exec(str);
    // console.log(res);
    
    

五. ES10 新特性

  1. Object.fromEntries 合并二维数组或map成对象
  2. trimStart 和 trimEnd 清除字符串空白
  3. flat (将多维数组转化为低维数组) ,参数为深度,是一个数字 和 flatMap
  4. Symbol.prototype.description 字符串描述

六. ES11 新特性

  1. 私有属性 变量#name,外部不能访问,要通过调用内部方法进行访问

  2. Promise.allSettled 和 Promise.all

    Promise.allSettled()
    
    	接受的结果与入参时的promise实例一一对应,且结果的每一项都是一个对象,告诉你结果和值,对象内都有一个属性叫“status”,用来明确知道对应的这个promise实例的状态(fulfilled或rejected),fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值
    
    Promise.all()
    
    	必须是接受参数中的所有promise实例都变为fulfilled状态,包装实例本身才会变为fullfilled状态,否则有一个接受参数中有一个rejected,则包装实例就是rejected状态
    
  3. String.prototype.matchAll

    let str = `<ul>
        <li>
          <a>肖生克的救赎</a>
          <p>上映时间:1994-09-10</p>
        </li>
        <li>
          <a>阿甘正传</a>
          <p>上映时间:1994-07-06</p>
        </li>
      </ul>`;
    const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
    
    const result = str.matchAll(reg);
    
    // for (let v of result) {
    // 	console.log(v);
    // }
    
    const arr = [...result];
    
    console.log(arr);
    
    
  4. 可选链操作符 ?.

    const obj = {
      foo: {
        bar: {
          baz: 42,
          fun: ()=>{}
        },
      },
    };
    
    // 不使用?. 不存在会报错
    let baz = obj && obj.foo && obj.foo.bar && obj.foo.bar.baz; 
    
    // 使用?. 不存在返回 undefined
    let baz = obj?.foo?.bar?.baz; // 结果:42
    
  5. 动态 import

    btn.onclick = function(){
    	import('./hello.js').then(module => {
    		module.hello();
    	})
    }
    
  6. BigInt类型

    let n = 2n;
    console.log(n, typeof(n));
    
  7. 绝对全局对象 globalThis