ES6-11特性

ES6特性

let

  • 不能重复声明变量
  • 块级作用域
    1
    2
    3
    4
    5
    for (let i = 0; i<length; i++) {
    btns[i].onclick = function () {
    console.log("hello" + i);
    }
    }
  • 不存在变量提升
  • 不影响作用域链

const

  • 常量需要赋初值
  • 常量的值不能修改
  • 块级作用域
  • 数组、对象的值可以修改,因为引用地址不变

变量的解构赋值

1
2
3
let [a, b, c] = anotherArray;
let {name, age, func} = anotherObj;

模板字符串

1
2
3
4
5
6
7

let str = `<ul>
<li>hello</li>
</ul>`
let name = "kong";
let name = `name: ${name}`;

对象的简化书写

1
2
3
4
5
6
7
8
9
10
11
12
let name = "kong";
let say = function () {
console.log("hello")
}
let obj = {
name,
say,
sayName () {
console.log("还可以这样简写方法")
}
}

箭头函数

  • 适合与this无关的
    1
    2
    3
    4
    5
    6
    let func = (a,b) => {
    return a + b;
    }
    let func = a => a**2;
    let func = (a,b) => a+b;

  • this 是静态的,始终指向函数声明时所在的作用域的this,call/apply/bind 都无法改变
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 例子
    ad.addEventListener("click", function () {
    setTimeout(() => {
    // this 指向箭头函数声明时所在的作用域的 this 也就是 ad 事件源对象
    this.style.background = 'pink';
    }, 2000);
    });

    let arr = [1,2,3,4,5,6]
    let res = arr.filter(item => item % 2 === 0);

  • 箭头函数不能作为构造器实例化对象,即不能使用new操作符
  • 不能使用 argument 对象

函数参数默认设置

1
2
3
4
5
6
7
8
9
10
11
12
13
function add(a, b, c = 10) {  
return a + b + c;
}

function connect({host="127.0.0.1", username, password}) {
console.log(host + "/" + username + password);
}
connect({
host: 'localhost',
username: 'kong',
password: '123456'
})

rest参数

  • rest 参数须放最后 func(a, b, ...args)
    1
    2
    3
    4
    5
    6

    function data(...args) {
    console.log(args)
    }
    data('kong', 'de', 'wen');

扩展运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function sayHello() {
console.log(arguments); // a,b,c
}
let data = ['a', 'b', 'c'];
sayHello(...data);

let data1 = ['a', 'b'];
let data2 = ['c', 'd'];
let data = [...data1, ...data2]; // ['a', 'b', 'c', 'd']

// 浅拷贝
let data1 = ['a', 'b'];
let data = [...data1];

// 将伪数组转换为真数组
let divs = document.getElementsByTagName('div');
let divArray = [...divs];

Symbol

  • 确保对象属性使用唯一标识符,不会发生属性冲突
1
2
3
4
5
6
7
8
9
let s = Symbol();
let s2 = Symbol("描述字符串");
let s3 = Symbol("描述字符串");
s2 != s3
// 全局符号
let s4 = Symbol.for("124")
let s5 = Symbol.for("124") // 查找注册表 存在就重用 s4
s4 === s5 // true s4 s5 指向地址相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// 借助Symbol在对象扩展方法 在不知道源是否含有同名方法 属性
let game = {
up: fucntion () {},
down: function () {}
};
let methods = {
up: Symbol(),
down: Symbol()
};
// 为game对象定义重名属性
game[methods.up] = function () {}
game[methods.down] = function () {}

// 方式2
let youxi = {
[Symbol('say')]: function () {},
[Symbol('hi')]: function () {}
}

迭代器

1
2
3
4
5
6
7
let youxi = ['a', 'b'];
// 返回指针对象 指向数据结构的起始位置
let iterator = youxi[Symbol.iterator]();
iterator.next(); // 返回数据第一个成员 { value: 'a', done: false }
iterator.next(); // 第二个
iterator.next(); // 第三个 { value: undefined, done: true }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 自定义迭代器遍历数据
const banji = {
stus: [ 'xiaoming', 'haitao', 'de', 'wem' ],
[Symbol.iterator] () {
let index = 0;
let _this = this;
return { // 需要一个对象 对象含有next 方法
next: function () {
if (index < _this.stus.length) {
return { value: _this.stus[index++], done: false };
} else {
return { value: undefined, done: true }
}
}
}
}
}
for (let v of banji) {
console.log(v);
}

生成器函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fucntion * gen() {
console.log("代码块一");
yield 'value1';
console.log("代码块二");
let two = yield 'value2';
console.log("代码块三: " + two);
yield 'value3';
console.log("代码块四");
}
let iterator = gen(); // 返回 iterator 迭代器对象
iterator.next(); // 执行代码块一,输出 代码块一
console.log(iterator.next()); // 执行代码块二, 这里输出 代码块二 {value: value2, done: false}
iterator.next('上一个yield'); // 输出 代码块三: 上一个yield 这个参数将作为上一个yield也就是第二个yield的返回
console.log(iterator.next()); // {value: undefined, done: true}

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
// 生成器函数实例 解决回调地狱
function one() {
setTimeout(()=>{
let data1 = "data1";
iterator.next(data1);
}, 1000)
}
function two() {
setTimeout(()=>{
let data2 = "data2";
iterator.next(data2);
}, 2000)
}
function three() {
setTimeout(()=>{
let data3 = "data3";
iterator.next(data3);
}, 3000)
}
function* gen() {
let data1 = yield one(); // data1
let data2 = yield two(); // data2
let data3 = yield three(); // data3
}
let iterator = gen();
iterator.next();

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 实例化 Promise 对象
const promise = new Promise(function(resolve, reject){
// 这里执行耗时异步 通过 resolve reject 改变状态
setTimeout(function(){
let data = '数据', err = '错误';
if ('成功') resolve(data);
else reject(err);
}, 1000)
})

promise.then(function(data){
console.log(data); // 数据
}, function(err){
console.log(err); // 错误
})

Promise 封装读取文件

1
2
3
4
5
6
7
8
9
10
11
12
13
const fs = require('fs');
const p = new Promise(function(resolve, reject){
fs.readFile("./file.txt", (err, data) => {
if (err) reject(err);
resolve(data);
})
})
p.then(function(value){
console.log(value);
}, function(reason){
console.log(reason);
})

Promise 封装Ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const promise = new Promise(function(resolve, reject){
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.apiopen.top/getJoke');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
})
promise.then((value) => {
console.log(value); // response数据
}, (reason) => {
console.log("error reason: " + reason);
})

Promise.prototype.then 链式调用

  • then() 返回一个 Promise 对象

  • 对象的状态由回调函数执行结果决定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const = result = p.then((value) => {
    // 1. 返回非 promise 对象 字符串 则 then()返回的promise对象状态为成功,值为该文本
    return 'hello文本一个';
    // 2. 抛出错误 则 then()返回的promise对象状态为失败,值为该错误
    throw new Error('出错了');
    throw '出错了';
    // 3. 返回 promise 对象, then()返回的promise对象状态根据返回的promise对象状态
    return new Promise((resolve, reject) => {
    resolve('成功')
    })
    }, (reason) => {
    // 该方法可以省略
    })
    console.log(result);
    result.then(value => {
    console.log(value); // hello文本一个
    })

  • 多次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
// 定义 ajax 请求:传入回调函数 success 和 fail
function ajax(url, success, fail) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url);
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
success && success(xmlhttp.responseText);
} else {
fail && fail(new Error('接口请求失败'));
}
};
}
// 封装获取 promise 对象方法
function getPromise(url) {
return new Promise((resolve, reject) => {
// 调用请求
ajax(url, (res) => {
if (res.retCode == 0) {
resolve('request success' + res);
} else {
reject({ retCode: -1, msg: 'network error' });
}
});
});
}

getPromise('a.json').then( value => {
console.log(value, '接着下次请求');
return getPromise('b.json'); // 返回有状态值的 promise 对象
}).then( value => {
console.log(value, '接着下次请求');
return getPromise('c.json');
}).then( value => {
console.log(value);
}).catch( err => {
console.log(err, '捕获错误');
})

Set 集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let s = new Set();
let s1 = new Set(['1','2','3']);

s1.size(); // 返回集合大小
s1.add('4'); // 添加元素
s1.delete('3'); // 删除元素
s1.has('1'); // 判断元素是否存在
s1.clear(); // 清除集合
for (let v of s1){ // 遍历集合
console.log(v);
}

// 数组去重
let arr = [1,2,3,4,3,4,2,5];
let arr1 = [...new Set(arr)];
// 数组交集
let arr1 = [1,2,3,4,3,4];
let arr2 = [1,2,5,6,7,4];
let result = [...new Set(arr1)].filter(item => new Set(arr2).has(item));
// 并集
let union = [...new Set([...arr1, ...arr2])];
// 差集
let diff = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item)));

Map

  • 键值对,键不限于字符串,可以任意类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let m = new Map();
m.set('name', 'kong');
m.set('func', function(){
console.log('hello');
})
let key = {
school: 'GT'
};
m.set(key, ['上海','广州','深圳']);
m.size();
m.delete('name');
m.get(key);
m.clear();
for (let v of m) {
console.log(v); // [key,value]
}

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Phone{
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
call(){
console.log('calling');
}
}
let phone = new Phone('华为', 4000);

// 静态成员
class Phone{
static name = '手机';
static change() {
console.log('我们属于类不属于实例')
}
}
Phone.name;
Phone.change();


// 继承
class SmartPhone extends Phone {
constructor(brand, price, color, size) {
super(brand, price); // Phone.call(this,brand,price)
this.color = color;
this.size = size;
}
// 重写
call() {
console.log('我重写了父类方法call')
}
photo(){
console.log('take photo');
}
}


// getter和 setter
// 适用于属性是动态计算出来的,设置是有要求的
class Phone{
get price(){
return '我是动态改变的';
}
set price(newVal){
console.log('赋值语句触发我');
}
}
let p = new Phone();
p.price = 'newVal'; // 打印 我是动态改变的

Number 的扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Number.EPSILON
function equal(a,b) {
if (Math.abs(a-b) < Number.EPSILON) return true;
else return false;
}
console.log(equal(0.1+0.2, 0.3)); // true

// 进制
let b = 0b101010;
let o = 0o777;
let d = 100;
let x = 0xff;

Number.isFinite(Infinity); // 是否无限
Number.isNaN(NaN); // 是否是数字
Number.parseInt('123');
Number.parseFloat('123.23asds');
Number.isInteger(2.5);
Number.trunc(2.5); // 抹除小数
Number.sign(100); // 正数 0 负数 分别返回 1 0 -1

Object对象方法扩展

1
2
3
4
5
6
7
8
9
10
11
// 类似 ===
Object.is(111, 111); // true
Object.is(NaN, NaN); // true

// 对象合并 会覆盖同名属性
Object.assign(obj1, obj2);

// 设置、获取原型
Object.setPrototypeOf(obj1, obj2);
Object.getPrototypeOf(obj1);

模块化

  • 防止命名冲突
  • 代码复用
  • 高维护性

模块暴露

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// module1.js 暴露
// 1.分别暴露
export let name = 'kong';
export function sayName(){
console.log('hello');
}

// 2. 统一暴露
export {
name,
sayName
}

// 3. 默认暴露
export default {
name: 'kong',
sayName: function (){
console.log('hello');
}
}

模块引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 引入 -->
<script type='module'>
// 1. 通用引入方式
import * as module1 from './module1.js';
// 默认暴露 调用
module1.default.sayName();

// 2. 解构赋值方式 针对: 分别暴露
import {name, sayName} from './module1.js';
import {name as nickName, sayName} from './module1.js';
// 对应默认暴露
import {default as module1} from './module1/js';

// 3. 简便引入 针对 默认暴露
import module1 from './module1.js';

</script>

babel 模块化代码转换

1
2
3
4
5
npm init -y
npm i babel-cli babel-preset-env browserify -D
npx babel src/js -d dist/js --presets=babel-preset-env // 转换
npx browserify dist/js/app.js -o dist/bundle.js // 打包

ES7特性

1
2
3
4
5
const arr = [1,2,3,4];
arr.includes(2); // true

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

ES8特性

async/await

  • async 函数返回值为 Promise对象
  • promise对象的结果由 async 函数执行返回值决定
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
// async
async function func(){
//返回非promsie对象 返回的 promise 对象状态值为 resolve('成功')
return '成功';
// 返回 reject
throw new Error('错误');
// 返回 promise 对象
return new Promise((resolve, reject) => {
resolve('yes');
reject('no');
})
}
const result = func();
result.then(value => {
console.log(value)
}, reason => {
console.warn(reason)
})

// await 须存在于async
let p = new Promise((resolve,reject) => {
resolve('数据');
})
let p2 = new Promise((resolve,reject) => {
reject('错误');
})
async function say(){
let result = await p; // 返回 promise 对象的成功状态下的值
console.log(result); // 输出 数据

// promise 失败状态下的值需要 try catch 捕获
try {
let res = await p2;
} catch (err) {
console.log(err); // 输出 错误
}
}

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
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function(){
if (xhr.readyState === 4) {
if (xhr.status >=200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status);
}
}
}
})
}
async function mainfunc(){
// 等待result1
let result1 = await sendAjax('https://api.apiopen.top/getJoke1');
// 等待result2
let result2 = await sendAjax('https://api.apiopen.top/getJoke2');
}

Object对象方法扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const school = {
name: 'kong',
age: 12,
addrss: 'dagang'
}
// 获取所有的键
Object.keys(school);
// 获取所有的值
Object.values(school);
// 返回键值对数组
Object.entries(school);
// 对象属性的描述对象
Object.getOwnPropertyDescriptors(school);

ES9特性

对象中 rest参数和扩展运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function connect({host, post, ...user}) {  
console.log(user.name + user.age);
}
connect({
host: 'localhost',
post: 8000,
name: 'kong',
age: 12
})

// 对象合并
let obj1 = { name: 'kong' }
let obj2 = { age: 12 }
let union = {...obj1, ...obj2};

正则扩展

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
43
44
45
46
47
// 命名捕获分组
let str = '<a href="http://www.baidu.com">百度</a>';
// 提取 url 和 文本
let reg = /<a href="(.*)">(.*)<\/a>/;
let res = reg.exec(str);
console.log("url: " + res[1]);
console.log("text: " + res[2]);

// 可定义别名
let str = '<a href="http://www.baidu.com">百度</a>';
// 提取 url 和 文本
let reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
let res = reg.exec(str);
console.log("url: " + res.groups.url); // 利用别名提取
console.log("text: " + res.groups.text);


// 正向断言
// 根据后面内容去匹配判断
let str = 'JS54321你好999拉拉';
let reg = /\d+(?=拉)/;
let res = reg.exec(str);
console.log(res); // 获取 999

// 反向断言
const reg = /(?<=好)\d+/;
const res =reg.exec(str);
console.log(res); // 获取 999

// dotAll dot . 除换行的任意字符
let str = `<ul>
<li>
<a>电影</a>
<p>上映时间</p>
</li>
<li>
<a>电影</a>
<p>上映时间</p>
</li>
</ul>`
let reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
let result;
let data = [];
while(result = reg.exec(str)) {
data.push({title: result[1], time: result[2]});
}
console.log(data);

ES10特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 二维数组转对象 与 Objec.entries()相反
const result = Object.fromEntries([
['name', 'kong'],
['xuexi', 'jiayou']
])
console.log(result); // {name: 'kong', xuexi: 'jiayou'}

// trim/trimStart/trimEnd 清除空白
let str = ' ilove you ';
str.trim(); // 'iloveyou'
str.trimStart(); // 'ilove you '
str.trimEnd(); // ' ilove you'

// 将多维数组转低维数组
arr.flat(2); // 3 维 转 1 维
arr.flatMap(item => [item * 10]); //Map后 顺便将二维转一维

// Symbol.prototype.description
Symbol('kong').description; // kong

ES11特性

  • 私有属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Person{
    name; // 公有
    #age; // 私有属性
    constructor(name, age) {
    this.name = name;
    this.#age = age;
    }
    myAge(){
    console.log(this.#age); // 内部可以访问
    }
    }
    const p = new Person('kong', 12);
    console.log(p.age); // 报错
    p.myAge(); // 12
  • Promise.allSettled()/Promise.all()

    1
    2
    3
    4
    5
    6
    // 返回成功值 和 一个对象数组 适用获取各个 promsie的状态
    const result = Promise.allSettled([promise1, promise2]);

    // 两个 promise 都成功才成功 适用各个 promse 都成功才下步执行操作
    const res = Promise.all([promise1, promise2]);

  • String.prototype.matchAll()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    let str = `<ul>
    <li>
    <a>电影</a>
    <p>上映时间</p>
    </li>
    <li>
    <a>电影</a>
    <p>上映时间</p>
    </li>
    </ul>`

    const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg;
    // 返回可迭代对象
    const result = str.matchAll(reg);
    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
    function main(config){
    // const dbHost = config && config.db && config.db.host;
    const dbHost = config?.db?.host;
    console.log(dbHost);
    }
    main({
    db: {
    host: '127.0.0.1',
    username: 'root'
    }
    })

  • 动态import

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // hello.js
    export function hello(){
    console.log('say hello');
    }

    // main.js
    btn.addEventListener('click', function(){
    // 返回 promise 对象
    import('./hello.js').then(module => {
    module.hello(); // say hello
    })
    })

  • BigInt

    1
    2
    3
    4
    5
    6
    7
    // 大整形
    let n = 1234n;
    BigInt(123); // 123n
    // 大整数运算
    let max = Number.MAX_SAFE_INTEGER;
    BigInt(max) + BigInt(10);

  • globalThis 忽视环境始终指向全局对象