一. ES6 语法
1.1 let/const关键字
- let声明的变量不存在预解析(变量提升)
- let变量不允许重复声明(在同一个作用域内)
- 块级作用域
- 不影响作用域链
- const声明的常量必须初始化
- 不允许重新赋值
- 块级作用域
- 当使用常量 const 声明时,请使用大写变量
1.2 变量的解构赋值
允许按照一定模式从数组和对象中提取值,对变量进行赋值(解构赋值)。
// 数组的解构赋值
let [a, b, c] = [1, 2, 3];
console.log(a, b, c);
let [d = 1, e, f] = [, 12, 3];
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(123, 456);
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三种状态:
- pending[等待]等待状态
- fulfilled[满足]满足状态
- rejected[拒绝]拒绝状态
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤。
Promise状态改变只有:
- 从pending变为fulfilled
- 从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方法
- Number.isFinite() 用来检查一个数值是否为有限的
- Number.isNaN() 用来检查一个值是否为 NaN
- Number.isInteger() 用来判断一个数值是否为整数
- Number.parseInt() 与 Number.parseFloat() :ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
- Number.isInteger() 判断一个数是否为整数
- Math.trunc() 将数字的小数部分抹掉
- Math.sign() 判断一个数到底是正数1 负数-1 还是零0
2.5 对象方法的扩展
-
Object.is() 判断两个值是否完全相等
console.log(Object.is(NaN, NaN)); // true console.log(NaN === NaN); //false -
Object.assign 对象的合并
const a = { name: "zs", age: 18, }; const b = { name: "ls", sex: "man", }; // 同名属性,取第二个参数对象的 console.log(Object.assign(a, b)); -
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之前的模块化规范有:
- CommonJS => NodeJS
- AMD => requireJS
- 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 函数
- async 函数的返回值为 promise对象
- promise 对象的结果由 async 函数执行的返回值决定
1.12 await 表达式
-
await 必须写在 async 函数中
-
await 表达式右侧值一般为 promise 对象
-
await 返回的是 promise 成功的值
-
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 正则扩展
-
正则扩展-命名捕获分组
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); -
正则扩展-反向断言
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); -
正则扩展-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 新特性
- Object.fromEntries 合并二维数组或map成对象
- trimStart 和 trimEnd 清除字符串空白
- flat (将多维数组转化为低维数组) ,参数为深度,是一个数字 和 flatMap
- Symbol.prototype.description 字符串描述
六. ES11 新特性
-
私有属性 变量#name,外部不能访问,要通过调用内部方法进行访问
-
Promise.allSettled 和 Promise.all
Promise.allSettled() 接受的结果与入参时的promise实例一一对应,且结果的每一项都是一个对象,告诉你结果和值,对象内都有一个属性叫“status”,用来明确知道对应的这个promise实例的状态(fulfilled或rejected),fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值 Promise.all() 必须是接受参数中的所有promise实例都变为fulfilled状态,包装实例本身才会变为fullfilled状态,否则有一个接受参数中有一个rejected,则包装实例就是rejected状态 -
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); -
可选链操作符 ?.
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 -
动态 import
btn.onclick = function(){ import('./hello.js').then(module => { module.hello(); }) } -
BigInt类型
let n = 2n; console.log(n, typeof(n)); -
绝对全局对象 globalThis