0%

【ES6】ES6笔记

ES6学习笔记

ES6

ECMAScrip?

ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言

ECMA-262?

Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个.

ECMAScript 与 JavaScript

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现.

为什么要学习 ES6?

  • ES6 的版本变动内容最多,具有里程碑意义;
  • ES6 加入许多新的语法特性,编程实现更简单、高效;
  • ES6 是前端发展趋势,就业必备技能;

ES6 兼容性

查看网址:http://kangax.github.io/compat-table/es6

前置知识

  • JavaScript
  • AJAX
  • NodeJS

ES6新特性

let

  • 声明局部变量

    1
    2
    3
    4
    let a;
    let b,c,d;
    let e = 100;
    let f = 100,g='test',h=[];
  • 不能重复声明
    与之相对应 var可以重复声明

    1
    2
    3
    //错误写法
    let a = 111;
    let b = 222;
  • 块级作用域
    只在当前代码块生效

    1
    2
    3
    4
    5
    6
    {
    var a = 111;
    let b = 222;
    }
    console.log(a);
    console.log(b);//报错
  • 不存在变量提升
    不允许let变量声明之前就调用

    1
    2
    3
    4
    console.log(test)//不报错
    var test = '111';
    console.log(test1)//报错
    let test1 = '222';
  • 不影响作用域链

    1
    2
    3
    4
    5
    6
    7
    {
    let test = 123;
    function fn() {
    console.log(test);//输出123(正常)
    }
    fn();
    }

const

const 关键字用来声明常量,const 声明有以下特点:

  • 声明必须赋初始值

    1
    2
    const A;//错误写法
    const B = 12;
  • 标识符一般为大写(习惯)

    1
    2
    const test = 'test';//不建议
    const TEST = 'test';
  • 不允许重复声明

    1
    2
    const TEST = 'test';
    const TEST = 'test1';//错误写法
  • 值不允许修改

    1
    2
    3
    4
    5
    const TEST = 'test';
    TEST = 'test2';//错误写法

    const ITEM = [1,2,3];
    ITEM.push(4);//允许写法,因为常量存的是ITEM的头指针
  • 块儿级作用域(局部变量)

变量解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

  • 数组的解构赋值

    1
    2
    3
    const F4 = ["一","二","三","四"];
    let [a,b,c,d] = F4;
    console.log(a + b + c + d); // 一二三四
  • 对象的解构赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const F3 = {
    name : "大哥",
    age : 22,
    sex : "男",
    xiaopin : function(){ // 常用
    console.log("我会演小品!");
    }
    }
    let {name,age,sex,xiaopin} = F3; // 注意解构对象这里用的是{}
    console.log(name + age + sex + xiaopin); // 大哥22男
    xiaopin(); // 此方法可以正常调用

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
字符串中可以出现换行符
可以使用 ${xxx} 形式引用变量

  • 声明

    1
    2
    let string = `我也一个字符串哦!`;
    console.log(string);
  • 内容中可以直接出现换行符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //错误写法
    //let string1 = '<ul>
    // <li>一</li>
    // <li>二</li>
    // <li>三</li>
    // <li>四</li>
    // </ul>';

    let string2 = `<ul>
    <li>一</li>
    <li>二</li>
    <li>三</li>
    <li>四</li>
    </ul>`;
    console.log(string2);
  • 变量拼接

    1
    2
    3
    let test1 = `AAAAAA`;
    let test2 = `${test1}BBBBBB`;
    console.log(test2)

简化对象和函数写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let name = "wx";
let change = function () {
console.log("do change function()");
};
const school = {
//完整写法
//name:name
//change:change
//简化写法
name,
change,
//声明简化
improve() {
console.log("do improve function()");
},
};
console.log(school);
school.change();
school.improve();

箭头函数

ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义

写法&特性

  • 声明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //正常写法
    var fn1 = function (a, b) {
    return a + b;
    };
    //箭头函数写法
    var fn2 = (a, b) => {
    return a + b;
    };
    console.log(fn1(1, 2));
    console.log(fn2(1, 2));
  • this是静态的
    this始终指向函数声明时所在作用域下的this值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function getName1() {
    console.log(this.name);
    }

    let getName2 = () => {
    console.log(this.name);
    };

    window.name = "wx1";
    let person = { name: "wx2" };
    getName1();
    getName2();

    getName1.call(person);
    getName2.call(person);
  • 不能作为构造实例化对象

    1
    2
    3
    4
    5
    6
    7
    let person = (name, age) => {
    this.name = name;
    this.age = age;
    };
    //此处报错
    let me = new person("wx", 20);
    console.log(me);
  • 不能使用 arguments 变量

    1
    2
    3
    4
    5
    //错误实例
    var fn2 = () => {
    console.log(arguments);
    };
    fn2(1, 2, 3);
  • 箭头函数的简写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //形参有且只有一个的时候,省略括号()
    let add5 = n => {
    return n + 5;
    };
    //当函数体只有一条语句的时候,省略花括号{}
    let pow = n => n * n;

    console.log(add5(5));
    console.log(pow(5));

场景

  • 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调

  • 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法

  • 1 回调里的this要使用当前div的this时,而不是window,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <body>
    <div id="test1" style="height: 200px; width: 200px; background: #66ccff"></div>
    <div id="test2" style="height: 200px; width: 200px; background: #39c5bb"></div>
    <script>
    let test1 = document.getElementById("test1");
    test1.addEventListener("click", function () {
    setTimeout(function () {
    this.style.background = "red";
    }, 2000);
    });

    let test2 = document.getElementById("test2");
    test2.addEventListener("click", function () {
    setTimeout(() => {
    this.style.background = "red";
    }, 2000);
    });
    </script>
    </body>
  • 2 回调的简写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const arr = [1, 2, 3, 4, 5, 6, 7, 8];
    const result1 = arr.filter(function (item) {
    //返回偶数
    if (item % 2 === 0) {
    return true;
    } else {
    return false;
    }
    });
    console.log(result1);

    const result2 = arr.filter((item) => item % 2 === 0);
    console.log(result2);

中函数参数的默认值

ES允许给函数的参数赋初始值

  • 形参初始值 具有默认值的参数一般位置要靠后(约定俗成)

    1
    2
    3
    4
    5
    function add(a, b, c = 10) {
    return a + b + c;
    }
    console.log(add(1, 2, 3));
    console.log(add(1, 2));
  • 与解构赋值结合

    1
    2
    3
    4
    5
    function connect({ host = "127.0.0.1", username, password, port }) {
    console.log(host + "," + username + "," + password + "," + port);
    }
    connect({ host: "baidu.com", username: "root", password: "root", port: 3306 });
    connect({ username: "root", password: "root", port: 3306 });

rest参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
详见

1
2
3
4
5
6
7
8
9
function data1() {
console.log(arguments);
}
data1("一", "二", "三", "四");

function data2(...args) {
console.log(args);
}
data2("一", "二", "三", "四");
  • rest参数只包括那些没有给出名称的参数,arguments包含所有参数
  • arguments 对象不是真正的数组,而rest 参数是数组实例,可以直接应用sort, map, forEach, pop等方法
  • arguments 对象拥有一些自己额外的功能
  • rest 参数之后不能再有其他参数(即,只能是最后一个参数),否则会报错
  • 函数的 length 属性,不包括rest参数。

扩展运算符

... 扩展运算符能将数组转换为逗号分隔的参数序列;
扩展运算符(spread)也是三个点(…)。
它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

写法

1
2
3
4
5
6
const data = ["一", "二", "三", "四"];
function log() {
console.log(arguments);
}
log(data);
log(...data);

应用

  • 数组合并

    1
    2
    3
    4
    5
    6
    7
    const data1 = ["一", "二", "三", "四"];
    const data2 = ["1", "2", "3", "4"];

    const data12_1 = data1.concat(data2);
    const data12_2 = [...data1, ...data2];
    console.log(data12_1);
    console.log(data12_2);
  • 数组克隆

    1
    2
    3
    4
    const data1 = ["一", "二", "三", "四"];
    const data2 = [...data1];
    console.log(data1);
    console.lg(data2);
  • 将伪数组转为真正数组

    1
    2
    3
    4
    const divs = document.querySelectorAll("div");
    const divArr = [...divs];
    console.log(divs);
    console.log(divArr);

Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。
它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
参考

写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let s1 = Symbol();
console.log(s1, typeof s1);

let s2 = Symbol("test");
let s3 = Symbol("test");
console.log(s2, typeof s2);
console.log(s3, typeof s3);
console.log("s2 === s3 : ", s2 === s3);

let s4 = Symbol.for("test");
let s5 = Symbol.for("test");
console.log(s4, typeof s4);
console.log(s5, typeof s5);
console.log("s4 === s5 : ", s4 === s5);

应用

  • 向对象中添加方法1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    let game = {
    up: () => console.log("game.up"),
    down: () => console.log("game.up"),
    };

    let methods = {
    up: Symbol(),
    down: Symbol(),
    };

    game[methods.up] = function () {
    console.log("methods.up");
    };
    game[methods.down] = function () {
    console.log("methods.down");
    };

    console.log(game);
  • 向对象中添加方法2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let game = {
    up: () => console.log("game.up"),
    down: () => console.log("game.up"),
    [Symbol()]: function () {
    console.log("methods.up");
    },
    [Symbol()]: function () {
    console.log("methods.down");
    },
    };
    console.log(game);

Symbol内置值:

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行;

内置Symbol的值 调用时机
1 Symbol.hasInstance 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
2 Symbol.isConcatSpreadable 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
3 Symbol.species 创建衍生对象时,会使用该属性
4 Symbol.match 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。
5 Symbol.replace 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。
6 Symbol.search 当该对象被 str. search (myObject)方法调用时,会返回该方法的返回值。
7 Symbol.split 当该对象被 str. split (myObject)方法调用时,会返回该方法的返回值。
8 Symbol.iterator 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器
9 Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
10 Symbol.toStringTag 在该对象上面调用 toString 方法时,返回该方法的返回值
11 Symbol.unscopables 该 对象指定了使用 with 关键字时,哪些属性会被 with环境排除。
  • 示例1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Person {
    static [Symbol.hasInstance](param) {
    console.log(param);
    console.log("我被用来检测类型了");
    return false;
    }
    }
    let o = {};
    console.log(o instanceof Person);
  • 示例2

    1
    2
    3
    4
    5
    const arr = [1, 2, 3];
    const arr2 = [4, 5, 6];
    // 合并数组:false数组不可展开,true可展开
    arr2[Symbol.isConcatSpreadable] = false;
    console.log(arr.concat(arr2));

迭代器

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

写法

1
2
3
4
5
6
7
8
9
const data1 = ["一", "二", "三", "四"];

console.log(data1);
for (const v in data1) {
console.log(v);
}
for (const v of data1) {
console.log(v);
}

原理

  1. 创建一个指针对象,指向当前数据结构的起始位置;
  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
  4. 每调用 next 方法返回一个包含 value 和 done 属性的对象;
1
2
3
4
5
6
7
8
const data1 = ["一", "二", "三", "四"];
let iterator = data1[Symbol.iterator]();
console.log("@", iterator);
console.log("@", iterator.next());
console.log("@", iterator.next());
console.log("@", iterator.next());
console.log("@", iterator.next());
console.log("@", iterator.next());

迭代器自定义遍历对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const data = {
name: "数据集合",
arrs: ["一", "二", "三", "四"],
[Symbol.iterator]() {
let index = 0;
return {
next: () =>
index < this.arrs.length
? { value: this.arrs[index++], done: false }
: { value: undefined, done: true },
};
},
};

console.log(data);
for (const v of data) console.log(v);

生成器

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同

写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function* gen() {
console.log("@", "------1-----");
yield "=======1=======";
console.log("@", "------2-----");
yield "=======2=======";
console.log("@", "------3-----");
yield "=======3=======";
console.log("@", "------4-----");
yield "=======4=======";
}
let test1 = gen();
console.log("#", test1);
console.log("&", test1.next());
console.log("&", test1.next());
console.log("&", test1.next());
console.log("&", test1.next());

let test2 = gen();
console.log("#", test2);
for (const v of test2) {
console.log("$", v);
}

生成器函数的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function* gen(arg) {
console.log(arg);
let one = yield 111;
console.log("111 =", one);
let two = yield 222;
console.log("222 =", two);
let there = yield 333;
console.log("333 =", there);
}
let test = gen("AAA");
console.log(test.next());
console.log(test.next("BBB"));
console.log(test.next("CCC"));
console.log(test.next("DDD"));

生成器函数实例

  1. 异步的回调地狱
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    setTimeout(() => {
    console.log(111);
    setTimeout(() => {
    console.log(222);
    setTimeout(() => {
    console.log(333);
    setTimeout(() => {
    console.log(444);
    }, 4000);
    }, 3000);
    }, 2000);
    }, 1000);
    可以写成为下面格式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    function one() {
    setTimeout(() => {
    console.log(111);
    iterator.next();
    }, 1000);
    }
    function two() {
    setTimeout(() => {
    console.log(222);
    iterator.next();
    }, 2000);
    }
    function there() {
    setTimeout(() => {
    console.log(333);
    iterator.next();
    }, 3000);
    }
    function four() {
    setTimeout(() => {
    console.log(444);
    iterator.next();
    }, 4000);
    }

    function* gen() {
    yield one();
    yield two();
    yield there();
    yield four();
    }

    let iterator = gen();
    iterator.next();
  2. 业务流程上的异步流程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 模拟获取: 用户数据 订单数据 商品数据
    function getUsers() {
    setTimeout(() => {
    let data = "用户数据";
    // 第二次调用next,传入参数,作为第一个的返回值
    iterator.next(data); // 这里将data传入
    }, 1000);
    }
    function getOrders() {
    setTimeout(() => {
    let data = "订单数据";
    iterator.next(data); // 这里将data传入
    }, 1000);
    }
    function getGoods() {
    setTimeout(() => {
    let data = "商品数据";
    iterator.next(data); // 这里将data传入
    }, 1000);
    }
    function* gen() {
    let users = yield getUsers();
    console.log(users);
    let orders = yield getOrders();
    console.log(orders);
    let goods = yield getGoods();
    console.log(goods);
    }
    let iterator = gen();
    iterator.next();

Promise

Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

写法 & 调用

Promise 构造函数: Promise (excutor) {}
Promise.prototype.then 方法
Promise.prototype.catch 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const psuc = new Promise(function (resolve, reject) {
setTimeout(function () {
let data = "成功返回的数据";
resolve(data);
}, 1000);
});
const perr = new Promise(function (resolve, reject) {
setTimeout(function () {
let err = "失败了返回的数据";
reject(err);
}, 2000);
});
psuc.then(
(value) => console.log(value),
(season) => console.log(season)
);
perr.then(
(value) => console.log(value), // 成功
(season) => console.log(season) // 失败
);

Promise.prototype.then

  • 如果回调函数中返回的结果是非promise类型的数据,状态为成功,返回值为对象的成功值resolved

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const p = new Promise((resolve, reject) =>
    setTimeout(() => resolve("用户数据"), 1000)
    );

    const result = p.then(
    (value) => {
    console.log(value);
    return "seccess";
    },
    (reason) => {
    console.log(reason);
    return "error";
    }
    );

    console.log(result);
  • 如果是promise类型的数据,此Promise对象的状态决定上面Promise对象p的状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const p = new Promise((resolve, reject) =>
    setTimeout(() => resolve("用户数据"), 1000)
    );

    const result = p.then(
    (value) => {
    console.log(value);
    return new Promise((resolve, reject) => {
    reject("error");
    });
    },
    (reason) => {
    console.log(reason);
    }
    );

    console.log(result);
  • 抛出错误

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const p = new Promise((resolve, reject) =>
    setTimeout(() => resolve("用户数据"), 1000)
    );

    const result = p.then(
    (value) => {
    console.log(value);
    throw new Error("失败啦!");
    },
    (reason) => {
    console.log(reason);
    }
    );

    console.log(result);
  • 链式调用,解决回调地狱问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    const p1 = new Promise((resolve, reject) =>
    setTimeout(() => resolve("用户数据1"), 3000)
    );
    const p2 = new Promise((resolve, reject) =>
    setTimeout(() => resolve("用户数据2"), 1000)
    );
    const result = p1
    .then(
    (value) => {
    console.log(value);
    return p2;
    },
    (reason) => {}
    )
    .then(
    (value) => {
    console.log(value);
    return value;
    },
    (reason) => {}
    );

    console.log(result);

应用

  • Promise封装读取文件
    一般写法

    1
    2
    3
    4
    5
    const fs = require("fs");
    fs.readFile("../resources/test.txt", (err, data) => {
    if (err) throw err;
    console.log(data.toString());
    });

    Promise封装后

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const fs = require("fs");
    const read = new Promise(function (resole, reject) {
    fs.readFile("../resources/test.txt", (err, data) => {
    if (err) {
    reject(err);
    } else {
    resole(data.toString());
    }
    });
    });

    read.then(
    (value) => console.log(value),
    (reason) => console.log("失败:" + reason.message)
    );
  • 回调地狱

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const fs = require("fs");
    // 2、调用方法,读取文件
    fs.readFile("resources/test.txt", (err, data1) => {
    fs.readFile("resources/test1.txt", (err, data2) => {
    fs.readFile("resources/test2.txt", (err, data3) => {
    let result = data1 + data2 + data3;
    console.log(result);
    });
    });
    });

    使用Promise优化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    const fs = require("fs");

    new Promise((resolve, reject) => {
    fs.readFile("resources/test.txt", (err, data) => {
    resolve(data);
    });
    })
    .then((value) => {
    return new Promise((resolve, reject) => {
    fs.readFile("resources/test1.txt", (err, data) => {
    resolve([value, data]);
    });
    });
    })
    .then((value) => {
    return new Promise((resolve, reject) => {
    fs.readFile("resources/test2.txt", (err, data) => {
    value.push(data);
    resolve(value);
    });
    });
    })
    .then((value) => {
    console.log(value.join("\r\n"));
    });
  • Promise封装Ajax请求
    一般写法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "https://api.apiopen.top/getJoke"); // 2、初始化
    xhr.send(); // 3、发送
    xhr.onreadystatechange = function () {
    // 判断状态
    if (xhr.readyState == 4) {
    // 判断响应状态码 200-299
    if (xhr.status >= 200 && xhr.status <= 299) {
    // 成功
    console.log(xhr.responseText);
    } else {
    // 失败
    console.error(xhr.status);
    }
    }
    };

    Promise封装后

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;

    const ajax = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "https://api.apiopen.top/getJoke"); // 2、初始化
    xhr.send(); // 3、发送
    xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
    if (xhr.status >= 200 && xhr.status <= 299) {
    console.log(xhr.responseText);
    resolve(xhr.responseText);
    } else {
    reject(xhr.status);
    }
    }
    };
    });

    ajax.then(
    (value) => console.log(value),
    (reason) => console.log(reason)
    );

catch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置p对象的状态为失败,并设置失败的值
reject("失败啦~!");
}, 1000);
});
p.then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);

p.catch((reason) => {
console.warn(reason);
});

Set

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator
接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。

基本属性和方法

size 返回集合的元素个数
add 增加一个新元素,返回当前集合
delete 删除元素,返回 boolean 值
has 检测集合中是否包含某个元素,返回 boolean 值
clear 清空集合,返回 undefined

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let s = new Set();
console.log(s, typeof s);

let s1 = new Set(["一", "二", "三", "四", "三"]);
console.log(s1); // 自动去重

// 1. size 返回集合的元素个数;
console.log(s1.size);

// 2. add 增加一个新元素,返回当前集合;
s1.add("五");
console.log(s1);

// 3. delete 删除元素,返回 boolean 值;
let result = s1.delete("三");
console.log(result);
console.log(s1);

// 4. has 检测集合中是否包含某个元素,返回 boolean 值;
let r1 = s1.has("二");
console.log(r1);

//5. 遍历集合
for (const v of s1) {
console.log(v);
}

// 6. clear 清空集合,返回 undefined;
s1.clear();
console.log(s1);

Set实践

数组去重

1
2
3
4
5
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let s1 = new Set(arr);
console.log(s1);
let arrres = [...new Set(arr)];
console.log(arrres);

求交集

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

求差集

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

求并集

1
2
3
4
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let arr2 = [3, 4, 5, 6, 5, 4, 3];
let union = [...new Set([...arr, ...arr2])];
console.log(union);

Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类
型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历

基本属性和方法

size 返回 Map 的元素个数
set 增加一个新元素,返回当前 Map
get 返回键名对象的键值
has 检测 Map 中是否包含某个元素,返回 boolean 值
clear 清空集合,返回 undefined

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Map集合
// 创建一个空 map
let m = new Map();
// 创建一个非空 map
let m2 = new Map([
["一", "1111"],
["二", "2222"],
]);
// 1. size 返回 Map 的元素个数;
console.log(m2.size);
// 2. set 增加一个新元素,返回当前 Map;
m.set("三", "3333");
m.set("四", "4444");
console.log(m);
// 3. get 返回键名对象的键值;
console.log(m.get("三"));
// 4. has 检测 Map 中是否包含某个元素,返回 boolean 值;
console.log(m.has("三"));
// 5. clear 清空集合,返回 undefined;
m.clear();
console.log(m);

class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。
基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

基本使用

先来看看ES5的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
// 手机 ES5写法
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
// 添加方法
Phone.prototype.call = function () {
console.log("我可以打电话!");
};
// 实例化对象
let HuaWei = new Phone("华为", 5999);
HuaWei.call();
console.log(HuaWei);

Es6写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Phone {
// 构造方法,名字是固定的
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 打电话,方法必须使用该方式写
call() {
console.log("我可以打电话!");
}
}
let HuaWei = new Phone("华为", 5999);
HuaWei.call();
console.log(HuaWei);

Class成员

ES5写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// class静态成员
function Phone() {}
Phone.name = "手机";
// class静态成员; ES5写法;
function Phone() {}
Phone.name = "手机";
Phone.change = function () {
console.log("我可以改变世界!");
};
let nokia = new Phone();
console.log(nokia.name); // undefined
// nokia.change();
// 报错:Uncaught TypeError: nokia.change is not a function
Phone.prototype.color = "黑色";
console.log(nokia.color); // 黑色
console.log(Phone.name);
Phone.change();
// 注意:实例对象和函数对象的属性是不相通的

ES6写法

1
2
3
4
5
6
7
8
9
10
11
class Phone {
// 静态属性
static name = "手机";
static change() {
console.log("我可以改变世界!");
}
}
let nokia = new Phone();
console.log(nokia.name);
console.log(Phone.name);
Phone.change();

构造函数继承

ES5构造函数继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function () {
console.log("我可以打电话!");
};
// 智能手机
function SmartPhone(brand, price, color, size) {
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone();
SmartPhone.prototype.constructor = SmartPhone;
// 声明子类的方法
SmartPhone.prototype.photo = function () {
console.log("我可以拍照!");
};
SmartPhone.prototype.game = function () {
console.log("我可以玩游戏!");
};
const chuizi = new SmartPhone("锤子", 2499, "黑色", "5.5inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();

ES6 class类继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
call() {
console.log("我可以打电话!!!!");
}
}
class SmartPhone extends Phone {
// 构造函数
constructor(brand, price, color, size) {
super(brand, price); // 调用父类构造函数
this.color = color;
this.size = size;
}
photo() {
console.log("我可以拍照!");
}
game() {
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米", 1999, "黑色", "5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();

重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
call() {
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone {
// 构造函数
constructor(brand, price, color, size) {
super(brand, price); // 调用父类构造函数
this.color = color;
this.size = size;
}
// 子类对父类方法重写
// 直接写,直接覆盖
// 注意:子类无法调用父类同名方法
call() {
console.log("我可以进行视频通话!");
}
photo() {
console.log("我可以拍照!");
}
game() {
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米", 1999, "黑色", "5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();

getter和setter设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Phone {
constructor(price1) {
this.price1 = price1;
}
get price() {
console.log("价格属性被读取了!");
return this.price1;
}
set price(value) {
console.log("价格属性被修改了!");
this.price1 = value;
}
}
let s = new Phone(1);
console.log(s.price);
s.price = 2999;
console.log(s.price);

数值扩展

Number.EPSILON

Number.EPSILON 是 JavaScript 表示的最小精度,EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16。

1
2
3
4
5
6
7
8
9
10
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}

console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1 + 0.2, 0.3));

进制

1
2
3
4
5
6
let a = 0b1010; //二进制
let b = 0o777; //八进制
let c = 100; //十进制
let d = 0xff; //十六机制

console.log(a, b, c, d);

Number.isFinite()

用来检查一个数值是否为有限的

1
2
3
4
console.log("100\t\t\t", Number.isFinite(100));
console.log("100 / 0\t\t", Number.isFinite(100 / 0));
console.log("10 / 3\t\t", Number.isFinite(10 / 3));
console.log("Infinity\t", Number.isFinite(Infinity));

Number.isNaN() :

用来检查一个值是否为 NaN

1
2
3
4
5
6
console.log("100\t\t\t", Number.isNaN(100));
console.log("100 / 0\t\t", Number.isNaN(100 / 0));
console.log("10 / 3\t\t", Number.isNaN(10 / 3));
console.log("Infinity\t", Number.isNaN(Infinity));
console.log("undefined\t", Number.isNaN(undefined));
console.log("NaN\t\t\t", Number.isNaN(NaN));

Number.parseInt() & Number.parseFloat()

1
2
3
4
5
6
console.log("100\t\t", Number.parseInt("100"));
console.log("100abc\t", Number.parseInt("100abc"));
console.log("abc100\t", Number.parseInt("abc100"));
console.log("100\t\t", Number.parseFloat("100"));
console.log("100abc\t", Number.parseFloat("100abc"));
console.log("abc100\t", Number.parseFloat("abc100"));

Math.trunc

用于去除一个数的小数部分,返回整数部分

1
console.log("99.999", Math.trunc(99.999));

Number.isInteger

用来判断一个数值是否为整数;

1
2
console.log("99", Number.isInteger(99));
console.log("99.999", Number.isInteger(99.999));

Math.sign

用来判断一个数是正数 负数还是零

1
2
3
console.log("-99\t", Math.sign(-999));
console.log("0\t", Math.sign(0));
console.log("99\t", Math.sign(999));

对象扩展

Object.is

比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)

1
2
3
4
5
console.log(Object.is(100, 100));
console.log(Object.is(100, 900));
console.log(Object.is(100, NaN));
console.log(Object.is(NaN, NaN));
console.log(NaN === NaN);

Object.assign

对象的合并,将源对象的所有可枚举属性,复制到目标对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const config1 = {
host: "localhost",
port: 3306,
name: "root",
pass: "root",
test: "test", // 唯一存在
};
const config2 = {
host: "192.168.0.1",
port: 9999,
name: "root4444",
pass: "root4444",
test2: "test2",
};
console.log(Object.assign(config1, config2));

proto && setPrototypeOf

setPrototypeOf 可以直接设置对象的原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const obj1 = {
name: "test",
};
const obj2 = {
test: ["一", "二", "三"],
};
console.log(obj1);
console.log(obj2);
// 设置原型
Object.setPrototypeOf(obj1, obj2);
console.log(obj1);
// 获取原型
console.log(Object.getPrototypeOf(obj1));
console.log(obj1);

模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

  • 优点
    1. 防止命名冲突
    2. 代码复用
    3. 高维护性
  • 模块化规范产品
    1. CommonJS => NodeJS、Browserify
    2. AMD => requireJS
    3. CMD => seaJS

ES6 模块化语法

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

  • export 命令用于规定模块的对外接口(导出模块)
  • import 命令用于输入其他模块提供的功能(导入模块)

简单使用

test.js

1
2
3
4
export let name = "test.js";
export function call() {
console.log("you call test.js function");
}

index.js

1
2
3
import * as test from "./test.js";
console.log(test.name);
test.call();

ES6导出数据语法

逐个导出

与上面简单使用的例子一样

统一导出

test.js

1
2
3
4
5
let name = "test.js";
function call() {
console.log("you call test.js function");
}
export { name, call };

index.js

1
2
3
import * as test from "./test.js";
console.log(test.name);
test.call();

默认导出

test.js

1
2
3
4
5
6
export default {
name: "test.js",
call: function () {
console.log("you call test.js function");
},
};

index.js

1
2
3
import * as test from "./test.js";
console.log(test.default.name);
test.default.call();

ES6引入数据语法

通用

上面ES6导出数据语法的所有例子都为通用写法

解构赋值形式

  • 一般情况
    test.js
    1
    2
    3
    4
    5
    let name = "test.js";
    function call() {
    console.log("you call test.js function");
    }
    export { name, call };
    index.js
    1
    2
    3
    import { name, call } from "./test.js";
    console.log(name);
    call();
  • 别名
    test1.js
    1
    2
    3
    4
    5
    let name = "test1.js";
    function call() {
    console.log("you call test1.js function");
    }
    export { name, call };
    test2.js
    1
    2
    3
    4
    5
    let name = "test2.js";
    function call() {
    console.log("you call test2.js function");
    }
    export { name, call };
    index.js
    1
    2
    3
    4
    5
    6
    import { name, call } from "./test1.js";
    import { name as name1, call as call2 } from "./test2.js";
    console.log(name);
    call();
    console.log(name1);
    call2();
  • 导入默认导出的模块
    test.js
    1
    2
    3
    4
    5
    6
    export default {
    name: "test.js",
    call: function () {
    console.log("you call test.js function");
    },
    };
    index.js
    1
    2
    3
    import { default as test } from "./test.js";
    console.log(test.name);
    test.call();

简便形式

只能针对默认暴露
test.js

1
2
3
4
5
6
export default {
name: "test.js",
call: function () {
console.log("you call test.js function");
},
};

index.js

1
2
3
import test from "./test1.js";
console.log(test.name);
test.call();

整合引入

test1.js

1
2
3
4
5
6
export default {
name: "test1.js",
call: function () {
console.log("you call test1.js function");
},
};

test2.js

1
2
3
4
5
let name = "test2.js";
function call() {
console.log("you call test2.js function");
}
export { name, call };

将js语法整合到一个文件app.js

1
2
import test1 from "./test1.js";
import * as test2 from "./test1.js";

在index.html引入

1
2
3
4
5
6
7
<!DOCTYPE html>
<html lang="cn">
<header><title>test</title></header>
<body>
<script src="./app.js" type="module"></script>
</body>
</html>

Babel对ES6模块化代码转换

安装工具

  • 初始化项目
    1
    npm init -y
  • babel-cli(命令行工具)
    1
    npm i babel-cli babel-preset-env browserify -D
  • babel-preset-env(ES转换工具)
    1
    npx babel src/js -d dist/js --presets=babel-preset-env
  • browserify(打包工具,项目中使用的是webpack)
    1
    npx browserify dist/js/app.js -o dist/bundle.js

操作示例

whatises6.7z

ES6模块化引入NPM包

例如导入jquery

  • 安装 jquery
    1
    npm i jquery
  • 在app.js使用jquery
    1
    2
    3
    //修改背景颜色为粉色
    import $ from 'jquery';// 相当于const $ = require("jquery");
    $('body').css('background','pink');

ES7新特性

Array.prototype.includes

判断数组中是否包含某元素,includes 方法用来检测数组中是否包含某个元素,返回布尔类型值。

1
2
let arr = [1, 2, 3, 4, 5];
console.log(arr.includes(1));

指数操作符

在 ES7 中引入指数运算符「」,用来实现幂运算,功能与 Math.pow 结果相同;
幂运算的简化写法,例如:2的10次方:2
10;

1
2
console.log(Math.pow(2,10))
console.log(2**10);

ES8新特性

async & await

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

async 函数

  1. async 函数的返回值为 promise 对象
  2. promise 对象的结果由 async 函数执行的返回值决定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function fn() {
// return 123; // 返回普通数据
// 若报错,则返回的Promise对象也是错误的
// throw new Error("出错啦!");
// 若返回的是Promise对象,那么返回的结果就是Promise对象的结果
return new Promise((resolve, reject) => {
// resolve("成功啦!");
reject("失败啦!");
});
}
const result = fn();
// console.log(result); // 返回的结果是一个Promise对象
// 调用then方法
result.then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);

await 表达式

  1. await 必须写在 async 函数中
  2. await 右侧的表达式一般为 promise 对象
  3. await 返回的是 promise 成功的值
  4. await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// async函数 + await表达式:异步函数
// 创建Prmise对象
const p = new Promise((resolve, reject) => {
resolve("成功啦!");
});
async function fn() {
try {
// await 返回的是 promise 成功的值
let result = await p;
console.log(result); // 成功啦!
} catch (e) {
console.log(e);
}
}
fn();

async 和 await 读取文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 导入模块
import { readFile } from "fs";
// 读取
function readText() {
return new Promise((resolve, reject) => {
readFile("./resources/test1.txt", (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
function readTest1() {
return new Promise((resolve, reject) => {
readFile("./resources/test2.txt", (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
function readTest2() {
return new Promise((resolve, reject) => {
readFile("./resources/test3.txt", (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
//声明一个 async 函数
async function main() {
let t0 = await readText();
let t1 = await readTest1();
let t2 = await readTest2();
console.log(t0.toString());
console.log(t1.toString());
console.log(t2.toString());
}
main();

async 和 await 结合发送ajax请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
let XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// async 和 await 结合发送ajax请求
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); // 1、创建对象
xhr.open("GET", url); // 2、初始化
xhr.send(); // 3、发送
xhr.onreadystatechange = function () {
// 4、事件绑定
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status <= 299) {
// 成功
resolve(xhr.responseText);
} else {
// 失败
reject(xhr.status);
}
}
}; // 4、事件绑定
});
}
// 测试
const result = sendAjax("https://api.apiopen.top/getJoke");
result.then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);

// 使用async和await
async function main() {
let result1 = await sendAjax("https://api.apiopen.top/getJoke");
console.log("\n", result1);
let result2 = await sendAjax("http://poetry.apiopen.top/sentences");
console.log("\n", result2);
let result3 = await sendAjax("https://api.apiopen.top/getWangYiNews");
console.log("\n", result3);
}
main();

对象方法扩展

Object.values

返回一个给定对象的所有可枚举属性值的数组;

1
2
3
4
5
6
// 对象方法扩展
let school = { name: "testname", age: 24, sex: "男" };
// 获取对象所有的键
console.log(Object.keys(school));
// 获取对象所有的值
console.log(Object.values(school));

Object.entries

返回一个给定对象自身可遍历属性 [key,value] 的数组

1
2
3
4
5
6
7
8
// 对象方法扩展
let school = { name: "testname", age: 24, sex: "男" };
// 获取对象的entries
console.log(Object.entries(school));
// 创建map
const map = new Map(Object.entries(school));
console.log(map);
console.log(map.get("name"));

Object.getOwnPropertyDescriptors:

返回指定对象所有自身属性的描述对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let school = { name: "testname", age: 24, sex: "男" };
// 返回指定对象所有自身属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
// 参考内容:
const obj = Object.create(null, {
name: {
value: "testname1", // 设置值
// 属性特性
writable: true, //是否可写
configuration: true, //是否可以删除
enumerable: true, //是否可以枚举
},
});
console.log(obj);

ES9新特性

Rest 参数

1
2
3
4
5
6
7
8
9
10
11
12
function connect({ host, port, ...user }) {
console.log(host);
console.log(port);
console.log(user);
}
connect({
host: "127.0.0.1",
port: 3306,
username: "root",
password: "root",
type: "master",
});

spread 扩展运算符

1
2
3
4
5
6
7
const One = { q: "1111" };
const Two = { w: "2222" };
const Three = { e: "3333" };
const Four = { r: "4444", z: "555555" };

const mangseng = { ...One, ...Two, ...Three, ...Four };
console.log(mangseng);

正则扩展

命名捕获分组

ES9 允许命名捕获组使用符号『?』,这样获取捕获结果可读性更强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let str = '<a href="http://www.baidu.com">百度</a>';
const reg = /<a href="(.*)">(.*)<\/a>/;
// 执行
const result = reg.exec(str);
console.log(result);
console.log(result);
// 结果是一个数组,第一个元素是所匹配的所有字符串
// 第二个元素是第一个(.*)匹配到的字符串
// 第三个元素是第二个(.*)匹配到的字符串
// 我们将此称之为捕获
console.log(result[1]);
console.log(result[2]);
// 命名捕获分组
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result1 = reg1.exec(str);
console.log(result1);
// 这里的结果多了一个groups
// groups:
// text:"百度"
// url:"http://www.baidu.com"
console.log(result1.groups.url);
console.log(result1.groups.text);

反向断言

ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选

1
2
3
4
5
6
7
8
9
10
let str = "JS5201314你知道么555啦啦啦";
// 需求:我们只想匹配到555
// 正向断言
const reg = /\d+(?=啦)/; // 前面是数字后面是啦
const result = reg.exec(str);
console.log(result);
// 反向断言
const reg1 = /(?<=么)\d+/; // 后面是数字前面是么
const result1 = reg.exec(str);
console.log(result1);

dotAll模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 正则扩展:dotAll 模式
// dot就是. 元字符,表示除换行符之外的任意单个字符
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>/;
// dotAll 模式
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
// const result = reg.exec(str);
// console.log(result);
let result;
let data = [];
while ((result = reg.exec(str))) {
console.log(result);
data.push({ title: result[1], time: result[2] });
}
console.log(data);

ES10 新特性

fromEntries

将二维数组或者map转换成对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 之前学的Object.entries是将对象转换成二维数组
// 此方法接收的是一个二维数组,或者是一个map集合
// 二维数组
const result = Object.fromEntries([
["name", "test"],
["age", 24],
]);
console.log(result);

const m = new Map();
m.set("name", "test");
m.set("age", 24);
const result1 = Object.fromEntries(m);
console.log(result1);

trimStart & trimEnd

1
2
3
4
5
6
7
// trimStart 和 trimEnd
let str = " test ";
console.log(str.trimLeft());
console.log(str.trimRight());
console.log(str.trimStart());
console.log(str.trimEnd());
console.log(str.trim());

flat

将高维数组转为低维数组

1
2
3
4
5
const arr1 = [1, 2, 3, 4, [5, 6], 7, [8, 9], 0];
console.log(arr1.flat());
const arr2 = [1, 2, 3, 4, [5, 6, [7, 8], 9], 0];
console.log(arr2.flat());
console.log(arr2.flat(2));

flatMap

1
2
3
4
5
6
7
const arr1 = [1, 2, 3, 4];
const result1 = arr1.map((item) => item * 10);
const result2 = arr1.map((item) => [item * 10]);
const result3 = arr1.flatMap((item) => [item * 10]);
console.log(result1);
console.log(result2);
console.log(result3);

Symbol.prototype.description

获取Symbol的字符串描述

1
2
let s = Symbol("test");
console.log(s.description);

ES11 新特性

类的私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 类的私有属性
class Person {
// 公有属性
name;
// 私有属性
#age;
#weight;
// 构造方法
constructor(name, age, weight) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro() {
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}

// 实例化
const girl = new Person("小兰", 18, "90kg");
console.log(girl);
// 公有属性的访问
console.log(girl.name);
// 私有属性的访问
console.log(girl.age); // undefined
// console.log(girl.#age); // 报错Private field '#age' must be declared in an enclosing class
console.log(" ");
girl.intro();

Promise.allSettled

获取多个promise执行的结果集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取多个promise执行的结果集
// 声明两个promise对象
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("商品数据——1");
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("失败啦");
}, 1000);
});
// 调用Promise.allSettled方法
const result = Promise.allSettled([p1, p2]);
console.log(result);
//都成功他才成功↓
const result1 = Promise.all([p1, p2]); // 注意区别
console.log(result1);

String.prototype.matchAll

用来得到正则批量匹配的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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);
console.log(result);
// 返回的是可迭代对象,可用扩展运算符展开
// console.log(...result);
// 使用for...of...遍历
// for (let v of result) console.log(v);
const arr = [...result];
console.log(arr);

可选链操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function main(config) {
// 传统写法
// const dbHost = config && config.db && config.db.host;
// 可选链操作符写法
const dbHost = config?.db?.host;
console.log(dbHost);
}
main({
db: {
host: "192.168.1.100",
username: "root",
},
cache: {
host: "192.168.1.200",
username: "admin",
},
});

动态 import 导入

动态导入模块,什么时候使用时候导入

test1.js

1
2
3
export function hello() {
alert("test.js");
}

app.js

1
2
3
4
5
6
7
8
// import * as m1 from "./hello.js"; // 传统静态导入
//获取元素
const btn = document.getElementById("btn");
btn.onclick = function () {
import("./test1.js").then((module) => {
module.hello();
});
};

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>动态 import</title>
</head>
<body>
<button id="btn">点击</button>
<script src="./src/js/app.js" type="module"></script>
</body>
</html>

BigInt

更大的整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// BigInt
// 大整型
let n = 100n;
console.log(n, typeof n);

// 函数:普通整型转大整型
let m = 123;
console.log(BigInt(m));

// 用于更大数值的运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max);
console.log(max + 1);
console.log(max + 2); // 出错了
console.log(BigInt(max));
console.log(BigInt(max) + BigInt(1));
console.log(BigInt(max) + BigInt(2));

globalThis

globalThis 对象 : 始终指向全局对象window

1
console.log(globalThis);

感谢查阅