ES6-11

Let

声明变量

声明一个变量

let a;

声明多个个变量

let b,c,d;

赋予初始值

let e =100;

赋予多个初始值

let f = 521,g = 'iloveyou', h= [];

声明变量的特性

变量不能重复声明(报错),var可以

let a = 1;

let a = 2;

作用于块级作用域

变量只在代码块里面有效,出了代码块以外就无效,读取不到

ES5作用域分三种:全局、函数、eval

ES6新增块级作用域

实例:

{

​ let a =1;

}

if else while for 都属于块级作用域

console.log(a); 会报错:显示没有定义a;

不存在变量提升

变量提升:代码在执行之前会提前收集变量(var 还有函数)的属性,会提前声明且赋予初始值undefinded

例如:

console.log(a) ; 输出undefined,如果使用let定义a就会报错

var a = '11111';

不影响作用域链

{

​ let school = 111;

​ function fn(){

​ console.log(school);

​ }

​ fn();

}

调用fn函数,因为函数内没有school变量,会向上一级的作用域里面找school变量,所以说虽然let是块级作用域,但是不影响作用域链的效果

Const(常用数组和对象)

声明常量(值不可以修改的)

const a = 1111;

一定要赋予初始值

const a;会报要初始化的错误

常量的值不能修改

a = '12346';会报错

块级作用域

{

​ const gamer = ’大飞‘

}

console.log(gamer);报错找不到gamer

对数组和对象的元素值修改,不算做对常量的修改,不会报错

const team = ['111','222','333','444','555'];

team.push('6666');

常量team的值改变了,但地址没有发生改变

变量的解构赋值

const team = ['aaa','bbb','ccc','ddd','ffff'];

let {aaa,bbb,ccc,ddd,fff} = team

模板字符串(``)

let a = 'afasf'

let b = ${a}hgwsedfgsdg

对象简化写法

ES6允许大括号里面,直接写入变量和函数,作为对象的属性和方法

let name = 'aaa';

let change = function(){

​ console.log('gsdgaga');

}

const school = {

​ name,

​ change,

​ improve:function(){ //可以省略冒号和function improve(){}

​ console.log("dfgsdgsdgsd");

​ }

}

箭头函数

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

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

静态this值

this是静态的。this始终指向函数声明时所在作用域下(当前所在的上层作用域)的this的值

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

window.name = 'shanguigu';
const school = {
    name: 'SHANGUIGU'
}
//直接调用
getName();
getName2();

//call方法调用
getName.call(school); 输出改变,为SHANGUIGU
getName2.call(school); 输出不改变,为shanguigu

箭头函数的this值是静态的,无论用什么方式去调用,this始终是指向箭头函数在声明时在作用域下的this值

扩展案例1:

let ad = document.getElementById('ad');
ad.addEventListener("click",function () {
    // //需要保存this的值
    // let _this = this;
    // //定时器
    // setTimeout(function () {
    //     //直接调用this其实是指向window
    //     _this.style.background = 'pink';
    // },2000)
    
    //定时器
    setTimeout( ()=>{
        this.style.background = 'pink';
    },2000)
});

扩展案例2:

let numbers = [5, 12, 9, 130, 44];
// let filtered = numbers.filter(function (number) {
//     if (number % 2 === 0 ){
//         return true;
//     }else {
//         return false;
//     }
// });

let filtered = numbers.filter(number => number %2 === 0 );

console.log(filtered);

不能作为构造实例化对象

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

let me = Person('agdgs',34);
console.log(me); //报错Person is not a constructor

不能使用arguments变量

箭头函数的简写

第一种情况:省略小括号,当形参有且只有一个的时候

// let add = (n) =>{
//     return n+n;
// }

let add = n =>{
    return n+n;
}
console.log(add(9));

第二种情况:省略花括号,当代码体只有一条代码的时候

此时return必须省略,而且代码的执行结果就是函数的返回值

// let pow = n => {
//     return n * n;
// }
// console.log(pow(9));

let pow = n =>  n * n;
console.log(pow(9));

rest参数(...标识符)

ES6引入rest参数

放于函数声明的形参位置

用于获取函数的实参,用来代替ES5的arguments获取参数方式

//rest 参数
function data(...args) {
    console.log(...args);
}
data('aaa','bbb','ccc');

rest参数必须放到参数最后

function fn(a,b,...args) {
    console.log(a);
    console.log(b);
    console.log(...args);
}
fn('aaa','bbb','ccc','ddd','eee');

arguments获取参数

function data() {
    console.log(arguments);
}
data('aaa','bbb','ccc');

扩展运算符(...标识符)

能将[数组]转化为逗号分隔的[参数序列]

放于函数调用的实参里

数组合并

const shuzhu_a = ['aaa','bbb'];
const shuzhu_b = ['ccc','ddd'];
//传统方式
// const c = shuzhu_a.concat(shuzhu_b);

const c = [...shuzhu_a,...shuzhu_b];
console.log(c);

数组克隆

const shuzhu = ['e','g','m'];
const kelong = [...shuzhu];
console.log(kelong);

伪数组转数组

const weishuzhu = document.querySelectorAll('div');
const shuzhu = [...weishuzhu];
console.log(shuzhu);

Symbol

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

Symbol特点

  1. Symbol的值是唯一的,用来解决命名冲突的问题
  2. Symbol值不能与其他数据进行运算
  3. Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
//创建Symbol,Symbol是函数
let s = Symbol();
let s1 = Symbol('尚硅谷');
let s2 = Symbol('尚硅谷');
//false
console.log(s1===s2);

//创建Symbol.for,此时Symbol是对象
//通过这种方式创建,可以通过描述字符串来得出唯一的Symbol值
let s3 = Symbol.for('尚硅谷');
let s4 = Symbol.for('尚硅谷');
//true
console.log(s3===s4);

Symbol使用场景

给对象添加方法

let game = {}

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

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

console.log(game);
let game = {
    name : 'nishuihan',
    [Symbol('say')]:function() {
        console.log('say');
    },
    [Symbol('tiequan')]:function() {
        console.log('tiequan');
    }
}

console.log(game);

Symbol内置值

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。

class Person {
    static [Symbol.hasInstance](){
        console.log("我被用来检测类型");
    }
}

let e = {}

console.log(e instanceof Person);
//输出:我被用来检测类型
//输出:false

迭代器

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

  1. ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费

  2. 原生具备 iterator 接口的数据(可用 for of 遍历)

​ a) Array

​ b) Arguments

​ c) Set

​ d) Map

​ e) String

​ f) TypedArray

​ g) NodeList

  1. 工作原理

​ a) 创建一个指针对象,指向当前数据结构的起始位置

​ b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员

​ c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员

​ d) 每调用 next 方法返回一个包含 value 和done 属性的对象

注:需要自定义遍历数据的时候,要想到迭代器。

自定义遍历数据

正常遍历方式

const xiaoshuo = ['西游记','三国演义','红楼梦','水浒传'];
//使用for...of是保留键值(西游记、三国演义、红楼梦、水浒传)来遍历数组
for (let v of xiaoshuo){
    console.log(v);
}
//使用for...in是保留键名(0、1、2、3)遍历数组

Symbol迭代器接口(方法)遍历

//声明一个对象
const xiaoshuo = {
    name:"小说",
    novel:['西游记','三国演义','红楼梦','水浒传'],
    //迭代器方法
    [Symbol.iterator](){
        //索引变量
        let index = 0;
        let _this = this;
        //需要定义返回对象
        return {
            //第一次要调用对象的 next 方法
            next : function () {
                if (index < _this.novel.length){
                    //需要返回一个对象
                    const result = {value: _this.novel[index],done:false};
                    index++;
                    return result;
                }else {
                    return {value: undefined,done: true};
                }
            }
        };
    }
};

//遍历上方对象
//正常遍历方式,但不符合面向对象的思想
// xiaoshuo.novel.forEach(result =>{
//     console.log(result);
// });

for (let x of xiaoshuo) {
    console.log(x);
}

生成器

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

实例1:

//生成器其实就是一个特殊的函数
//异步编程  纯回调函数(node fs、ajax、mongodb)
//函数代码的分隔符
function * gen() {
    // console.log(111);
    yield 111;
    // console.log(2222);
    yield 222;
    // console.log(3333);
    yield 333;
    // console.log(4444);
    yield 444;
}

let iterator = gen();
console.log(iterator.next()); //{value: 111, done: false}
console.log(iterator.next()); //{value: 222, done: false}
console.log(iterator.next()); //{value: 333, done: false}
console.log(iterator.next()); //{value: 444, done: false}
console.log(iterator.next()); //{value: undefined, done: true}

实例2:

//生成器函数在异步任务下的表现
//异步编程 定时器(异步任务)避免回调地狱(回调中套回调)
function one() {
    setTimeout(()=>{
        let data = "用户数据";
        //第二次调用next,当前实参会作为第一个yield语句的返回结果
        iterator.next(data);
    },1000)
}

function two() {
    setTimeout(()=>{
        let data = "订单数据";
        //第三次次调用next,当前实参会作为第二个yield语句的返回结果
        iterator.next(data);
    },2000)
}

function three() {
    setTimeout(()=>{
        let data = "商品数据";
        //第四次调用next,当前实参会作为第三个yield语句的返回结果
        iterator.next(data);
    },3000)
}

function * gen() {
    let users = yield one();
    console.log(users);

    let orders = yield two();
    console.log(orders);

    let goods = yield three();
    console.log(goods);
}

let iterator = gen();
//第三次次调用next
iterator.next();

Promise

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

实例解析

实例

//实例化Promise对象
        const p = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                resolve('good');
            },1000)
        });

        //指定回调
        const result = p.then( value => {
            console.log(value);  //good
            //1.非 promise 类型的属性
            // return 123;
            //2.是 promise 对象
            // return new Promise((resolve, reject) => {
            //     // resolve('OK');
            //     reject('error');
            // })
            //3.抛出错误
            throw new Error('Error');

        }, reason => {
            console.log(reason);
            return 321;
        });

        console.log(result);
        
        //链式调用
        p.then(value => {},reason => {}).then(value => {},reason => {});

解析

实例化Promise对象

new Promise()会接收一个函数类型值的参数function () {},函数类型值的参数默认为resolvereject,通过调用resolve和reject这两个函数来改变promise对象(p)的状态,当调用resolve时,对象(p)的状态会变为成功。反之调用reject表示失败。

回调then方法

promise对象(p)还能调用then方法,then方法的返回结果是Promise对象对象状态由回调函数的执行结果决定,且then方法参数是两个函数类型,这两个函数类型都有一个形参,成功的形参一般设为value,失败的设为reason。value对应的是上方的resolve,而reason对应的是reject。

  1. 如果假设对象fn的回调函数中返回的结果是非promise类型的对象,对象fn的返回结果也会是状态为成功的promise对象

异步封装读取文件

多个异步任务的情况下,代码会不断缩进,使用Promise能避免不断缩进的情况

const fs = require('fs')
// fs.readFile('let.html',(err,data)=>{
//     if (err) throw err;
//     console.log(data.toString());
// });

//多个异步任务的情况下,代码会不断缩进,使用Promise能避免不断缩进的情况
const p = new Promise(function (resolve, reject) {
    fs.readFile('let1.html',(err,data)=>{
        if (err) reject(err);
        resolve(data)
    })
})

p.then(function (value) {
    console.log(value.toString());
},function (reason) {
    console.error(reason);
})

封装AJAX请求

const p = new Promise((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);
           }
       }
   }
});

//指定回调
p.then( value => {
            console.log(value);
        }, reason => {
            console.log(reason);
        });

实践练习-链式调用多个文件内容读取

//多个异步任务的情况下,代码会不断缩进,形成回调地狱,使用Promise能避免不断缩进的情况
const p = new Promise(function (resolve, reject) {
    fs.readFile('let1.html',(err,data)=>{

        resolve(data);
    })
})

p.then(value => {
    return new Promise(((resolve, reject) => {
        fs.readFile('let2.html',(err,data)=>{
            resolve([value,data]);
        })
    }));
}).then(value => {
    return new Promise(((resolve, reject) => {
        fs.readFile('let3.html',(err,data)=>{
            value.push(data);
            resolve(value);
        })
    }))
})

catch方法

const p = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        reject('good');
    },1000)
});


p.catch(function (reason) {
    console.warn(reason);
});

集合

集合Set介绍与API方法

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯

一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进

行遍历,集合的属性和方法:

\1) size 返回集合的元素个数

\2) add 增加一个新元素,返回当前集合

\3) delete 删除元素,返回 boolean 值

\4) has 检测集合中是否包含某个元素,返回 boolean 值

\5) clear 清空集合,返回 undefined

<!--    声明集合Set    -->
let s = new Set();
let s2 = new Set(['aaa','bbb','ccc','ddd','aaa']);

//添加新元素
// s2.add('eee');
//删除元素
// s2.delete('aaa');
//检测是否存在
// console.log(s2.has('eee'));
//清空
// s2.clear();

//遍历集合
for (let v of s2){
    console.log(v);
}
// console.log(s2);

集合Set实践

<!--    声明集合Set    -->
let s2 = ['aaa','bbb','ccc','ddd','aaa','eee','ccc','bbb'];

//数组去重
// let arr1 = [...new Set(s2)];
//交集
let s3 = ['bbb','eee','aaa','ccc','bbb'];
// let arr1 = [...new Set(s2)].filter(item=>{
//     let arr2 = new Set(s3);
//     if (arr2.has(item)){
//         return  true;
//     }else {
//         return false;
//     }
// });
//代码优化
// let arr1 = [...new Set(s2)].filter(item => new Set(s3).has(item));
// console.log(arr1);

//并集
// let union = new Set([...s2,...s3]);
// console.log(union);
//
// let union1 = [...new Set([...s2,...s3])];
// console.log(union1);


//差集
let diff = [...new Set(s2)].filter(item => !new Set(s3).has(item))
console.log(diff);

Map介绍与API

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”

的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了

iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。 Map 的属

性和方法:

\1) size 返回 Map 的元素个数

\2) set 增加一个新元素,返回当前 Map

\3) get 返回键名对象的键值

\4) has 检测 Map 中是否包含某个元素,返回 boolean 值

\5) clear 清空集合,返回 undefined


Class类

ES6 提供了更接近传统语言的写法,引入了 Class(类) 这个概念,作为对

象的模板。通过 class 关键字,可以定义类。基本上, ES6 的 class 可以看作只是

一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象

原型的写法更加清晰、更像面向对象编程的语法而已。

知识点:

\1) class 声明类

\2) constructor 定义构造函数初始化

\3) extends 继承父类

\4) super 调用父级构造方法

\5) static 定义静态方法和属性

\6) 父类方法可以重写

静态成员

函数对象和实例对象的属性不相通

<!--    函数对象和实例对象的属性不相通    -->
        //函数对象
        // function Phone() {
        //
        // }
        <!-- 相当于静态属性属于函数对象 -->
        // Phone.name = 'aaa';
        // Phone.change = function () {
        //     console.log('bbb');
        // }

        //等同于上方代码
        class Phone {
            static name = 'aaa';
            static change(){
                console.log('bbb');
            }
        }
        <!---->
        Phone.prototype.size = '5cm';

        //实例对象
        let n = new Phone();
        console.log(n.name);//undefined
        console.log(Phone.name);//aaa
        n.change();//undefined
        console.log(n.size);//5cm

构造函数继承(ES5)

function Phone(brand,price) {
    this.brand = brand;
    this.price = price;
}
Phone.prototype.call = function () {
    console.log("call");
}

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('ccc');
}

smartPhone.prototype.playGame = function () {
    console.log('ddd');
}

const p = new smartPhone('aaa',25235,'black','5cm');
console.log(p);

Class的类继承(ES6之后)

使用super调用父类的构造函数的构造方法

class Phone{
            //构造方法
            static key = 'key';
            constructor(brand,price,key) {
                this.brand = brand;
                this.price = price;
                this.key = key;
            }

            call(){
                console.log(this.brand);
            }
        }
        class SmartPhone extends Phone{
            //构造方法
            constructor(brand,price,color,size,key) {
                //使用super调用父类的构造函数的构造方法
                super(brand,price,key);
                this.color = color;
                this.size = size;
                //调用父类的静态属性的 方法一
                // this.key = SmartPhone.key;
                this.key = key;
            }

            photo(){
                console.log('photo');
            }

            playGame(){
                console.log('playGame');
            }
        }

        const sp = new SmartPhone('mi',1234,'black','7cm');
        //调用父类的静态属性的 方法二
        console.log(SmartPhone.key);
        //调用父类的静态属性的 方法一
        // console.log(sp.key);
        console.log(sp);

Class的getter和setter

class Phone {
    get price(){
        console.log('读取价格');
        return 126854;
    }

    set price(p){
        if (p<123){
            console.log('small');
        }else {
            console.log('big');
        }
    }
}

let pri = new Phone();

//Get
console.log(pri.price);
//Set
pri.price = 126;

数值扩展

二进制和八进制

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

let a = 0b1010; //二进制
let b = 0o777; //八进制
let c = 100; //十进制
let d = 0xfff;  //十六进制

Number.isFinite()与Number.isNaN()

Number.isFinite() 用来检查一个数值是否为有限的

Number.isNaN() 用来检查一个值是否为 NaN

console.log(Number.isFinite(Infinity)); //无穷(false) )

Number.parseInt()与Number.parseFloat()

ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。

parseInt()字符串转整数

console.log(Number.parseInt('5164654佛覅哦')); //5164654

parseFloat()字符串转浮点数

console.log(Number.parseFloat('7.5164654佛覅哦')); //7.5164654

Number.isInteger()

Number.isInteger() 用来判断一个数值是否为整数

Math.trunc()

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

console.log(Math.trunc(7.5164654)); //7

Math.sign()

判断一个数字为正数、零还是负数

1 正数

0 零

-1 负数

console.log(Math.sign(400)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-41.1)); //-1

对象扩展

Object.is

比较两个值是否严格相等

<!--    等同于===,除了NaN    -->
console.log(Object.is(100,100));    //true
console.log(Object.is(NaN,NaN));    //true
console.log(NaN === NaN);   //false

Object.assign

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

//以前对象config1为基准,后面对象config2中有同属性名的属性值覆盖前对象config1的
console.log(Object.assign(config1,config2));

getPrototypeOf 、 setPrototypeOf

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

const school = {
    name: '清华'
};

const cities =  {
    diqu: ['beijing','shanghai','shenzhen']
};

Object.setPrototypeOf(school,cities);
console.log(Object.getPrototypeOf(school));
console.log(school);

模块化

模块化的好处

模块化的优势有以下几点:

\1) 防止命名冲突

\2) 代码复用

\3) 高维护性

模块化规范产品

ES6 之前的模块化规范有:

​ 纸面规范 应用实例

\1) CommonJS => NodeJS 、Browserify(前端代码打包)

\2) AMD => requireJS(浏览器端)

\3) CMD => seaJS(浏览器端)

ES6模块化语法

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

export 命令用于规定模块的对外接口

import 命令用于输入其他模块提供的功能

模块暴露方式

分别暴露

统一暴露

默认暴露

export defalut{

​ //加暴露数据

}

ES6引入模块数据方式

通用引入

import * as m1 from "m1.js";
import * as m2 from "m2.js";

解构赋值形式

import {school,teach} from "./js/m1.js";
import {school as sch,findJob} from "./js/m2.js";
import {default as m3} from "./js/m3.js";

console.log(school,teach);

简便形式(针对默认暴露)

import m3 from "./js/m3.js"

console.log(m3);

浏览器使用ES6模块化数据

方法一

使用标签,在标签里写代码

<script type="module">
    import {school,teach} from "./js/m1.js";
    import {school as sch,findJob} from "./js/m2.js";
    import {default as m3} from "./js/m3.js";

    console.log(school,teach);
</script>

方法二

用标签src属性去引入文件,类型设置为module

<script src="./js/m4.js" type="module"></script>

babel对ES6模块化转换

  1. 语法兼容性转换
    ES6 模块化使用 importexport 语法,而旧版 JavaScript 环境不支持这些语法。Babel 可以将它们转换为 CommonJS 模块形式(如 require()module.exports):

    • ES6 代码:

      javascript复制代码import add from './math.js';
      export const multiply = (a, b) => a * b;
      
    • Babel 转换后:

      javascript复制代码const add = require('./math.js');
      exports.multiply = (a, b) => a * b;
      
  2. 通过插件实现模块化转换
    Babel 使用 @babel/preset-env@babel/plugin-transform-modules-commonjs 等插件来处理模块语法转换,确保代码在 Node.js 和旧版浏览器中兼容。

  3. Tree Shaking 支持
    Babel 与现代打包工具(如 Webpack)结合时,可以保留 ES6 模块化结构,支持 Tree Shaking 优化,减少未使用代码的打包。

总结

Babel 的核心作用是确保 ES6 模块化代码能够在不支持现代模块系统的环境中正常运行,同时通过插件体系提供灵活的配置选项,以满足不同项目的需求。

使用方式

初始化npm npm init --yes

安装工具babel npm i babel-cli babel-cli babel-preset-env browserify -D

转换ES6 npx babel js -d brower-js --presets=babel-preset-env

打包 npx browserify brower-js/m4.js -o brower-js/bundle.js

ES7新特性

Array.prototype.includes

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

const shuzu = ['发呼呼','放假放','阿吉覅','哦破发键盘'];

console.log(shuzu.includes('发呼呼'));     //true
console.log(shuzu.includes('发呼呼23'));   //false

指数操作符

在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同

console.log(2 ** 11);           //2024
console.log(Math.pow(2,12));    //4096

ECMASript 8 新特性

async await

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

async 函数

  1. async 函数的返回结果为 promise 对象

  2. async函数的promise 对象的结果和状态由 async 函数执行的返回值决定。如果回调函数的返回结果为非Promise对象,那回调函数的返回结果为async函数的返回值,且状态为成功;回调函数的返回结果为抛出错误,async函数的返回值为回调函数的报错原因,状态为错误;回调函数的返回结果为Promise对象,返回值和状态都由这个Promise对象决定。

await 表达式

  1. await 必须写在 async 函数中

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

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

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

const p = new Promise((resolve, reject) => {
    reject("失败了");
});

async function main() {
    try{
        let result = await p;
        console.log(result);
    }catch (e) {
        console.log(e);
    }
}

main();

async和await结合读取文件内容

const fs = require('fs')

function m1() {
    return new Promise((resolve, reject) => {
        fs.readFile('js/m1.js',(err,data)=>{
            if (err) throw err;
            resolve(data);
        });
    })
}

function m2() {
    return new Promise((resolve, reject) => {
        fs.readFile('js/m2.js',(err,data)=>{
            if (err) throw err;
            resolve(data);
        });
    })
}

function m3() {
    return new Promise((resolve, reject) => {
        fs.readFile('js/m3.js',(err,data)=>{
            if (err) throw err;
            resolve(data);
        });
    })
}

async function main() {
    let mR1 = await m1();
    let mR2 = await m2();
    let mR3 = await m3();

    console.log(mR1.toString());
}

main()

async和await结合发送ajax请求

function sAjax(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 main() {
    let sajax = await sAjax('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=2');
    console.log(sajax);
}

main();

Object.values 和 Object.entries

Object.values()方法

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

Object.entries()方法

返回一个给定对象自身可遍历属性 [key,value] 键值对的数组,键值对(集合对象)转化为数组,方便创建Map

const school = {
  name : "清北",
  cities: ['北京','上海','广州'],
  kemu : ['前端','后端','Python','Java']
};

// //获取对象所有的键
// console.log(Object.keys(school));
// //获取对象所有的值
// console.log(Object.values(school));
//获取对象所有的键值对,转化为数组
console.log(Object.entries(school));
//创建Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));

Object.getOwnPropertyDescriptors()

对象属性的描述对象

console.log(Object.getOwnPropertyDescriptors(school));

通过Object.create对象时,属性描述对象的结构。

/*
* 参数1:原型对象
* 参数2:描述对象(必须是对象)
* */
const obj  =Object.create(null,{
    name :{
        value:'清北',
        //属性特性
        //是否可写
        writable:true,
        //是否可以删除
        configurable:true,
        //是否可以连续
        enumerable:true
    }
})

console.log(Object.getOwnPropertyDescriptors(obj));

ES9新特性

扩展运算符与rest参数

Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,

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

function connect({host,type,...user}) {
    console.log(host);
    console.log(type);
    console.log(user);
}

connect({
    host:'127.0.0.1',
    port:'3306',
    username:'root',
    password:'root',
    type:'Get'
})

127.0.0.1
Get

对象合并

const skillOne = {
    q:'天音波',
}

const skillTwo = {
    w:'金钟罩',
}

const skillThree = {
    e:'天雷破',
}

const skillFour = {
    r:'猛龙摆尾',
}

const skill = {skillOne,skillTwo,skillThree,skillFour}
const skill1 = {...skillOne,...skillTwo,...skillThree,...skillFour}
console.log(skill);
console.log(skill1);

正则扩展

命名捕获分组

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

let str = '<a href="http://www.atguigu.com">尚硅谷</a>';

// const reg = /<a href="(.*)">(.*)<\/a>/;
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;

const result = reg.exec(str);

// console.log(result[1]);
// console.log(result[2]);
console.log(result.groups.url);
console.log(result.groups.text);

正向和反向断言

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

		let str = 'JS5211314 你知道么 555 啦啦啦';
        //正向断言
        const reg1 = /\d+(?=\s*啦)/; //\s*允许空格出现0次或多次
        const result1 = reg1.exec(str);
        console.log(result1);
        // //反向断言
        // const reg2 = /(?<=么)\d+/;
        // const result2 = reg2.exec(str);
        // console.log(result2);

dotAll模式

正则表达式中点.匹配除回车外的任何单字符,标记『s』改变这种行为,允许行

终止符出现

let str = `
    <ul>
        <li>
            <a>三国演义</a>
            <p>上映日期:1946年6月13日</p>
        </li>
        <li>
            <a>水浒传</a>
            <p>上映时间:2089年8月21日</p>
        </li>
    </ul>
        `;
// const reg = /<li>\s+<a>(?<title>.*?)<\/a>\s+<p>(?<date>.*?)<\/p>.*?<\/li>/;
const reg = /<li>.*?<a>(?<title>.*?)<\/a>.*?<p>(?<date>.*?)<\/p>.*?<\/li>/gs;        //g 标志表示全局匹配全部符合要求的,s 标志使 . 能够匹配换行符


//获取值方法一: 多次使用.exec()
// reg.exec(str)是单次调用匹配 的方法。当正则表达式包含全局标志 g 时,exec 会在每次调用后记录它的匹配位置,下次调用从该位置继续。由于你只调用了一次 exec,它仅匹配到第一条数据。
// const result1 = reg.exec(str);
// const result2 = reg.exec(str);
// console.log(result1);
// console.log(result2);

//获取值方法二: while循环来多次使用.exec()
// let result;
// const data = [];
// //持续判断result值是否存在,存在就输出,否则退出循环
// while (result = reg.exec(str)){
//     data.push({title:result.groups.title,date:result.groups.date})
// }
// console.log(data);

//获取值方法三:   matchAll
const result = str.matchAll(reg);
for (const resultKey of result) {
    console.log(resultKey.groups.title);
    console.log(resultKey.groups.date);
}

ES10新特性

Object.fromEntries

Object.fromEntries和Object.entries是一对互逆运算。

Object.fromEntries()方法将键值对数组转换为对象‌。

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组‌。

//键值对转化为数组
const school = {
    name : "清北",
    cities: ['北京','上海','广州'],
    kemu : ['前端','后端','Python','Java']
};
console.log(Object.entries(school));	//输出:[Array(2), Array(2), Array(2)]

//数组转化为键值对
const entries = [['x', 1], ['y', 2]];
const obj = Object.fromEntries(entries);
console.log(obj);		//输出:{x: 1, y: 2}

trimStart和trimEnd

et str = '    I Love You     ';
console.log(str.trim());    //清除全部空格
console.log(str.trimStart());       //清除左边的全部空格,和trimLeft()有相同效果
console.log(str.trimEnd());         //清除右边的全部空格,和trimRight()有相同效果

Array.prototype.flat与flatMap

Array.prototype.flat

//将多维数组转化为低维数组
const arr = [1,2,3,4,[5,6,[7,8,9]]];
//参数为深度,默认是1
console.log(arr.flat(1));       //输出为:[1, 2, 3, 4, 5, 6, [7, 8, 9]]

console.log(arr.flat(2));       //输出为:[1, 2, 3, 4, 5, 6, 7, 8, 9]

flatMap

const words = ["hello world", "flatMap is great"];
const result = words.flatMap(sentence => sentence.split(" "));
console.log(result);
// ["hello", "world", "flatMap", "is", "great"]

经验

const arr = [1, 2, 3, 4, [5, 6, 7, 8, 9]];
// console.log(arr.flatMap(item => [item * 10]));      //输出为:[10, 20, 30, 40, NaN]
//item 为数组 [5, 6, 7, 8, 9],执行 [5, 6, 7, 8, 9] * 10 返回 NaN,因为数组不能直接用于乘法运算。

const flattened = arr.flat().map(item => item * 10);        //flat()默认参数为1
console.log(flattened); // [10, 20, 30, 40, 50, 60, 70, 80, 90]

Symbol.prototype.description

let s = Symbol('烧过水的');
console.log(s.description);         //烧过水的

ECMASript 11新特性

String.prototype.matchAll

let str = `
    <ul>
        <li>
            <a>三国演义</a>
            <p>上映日期:1946年6月13日</p>
        </li>
        <li>
            <a>水浒传</a>
            <p>上映时间:2089年8月21日</p>
        </li>
    </ul>
        `;

        const reg = /<li>.*?<a>(?<title>.*?)<\/a>.*?<p>(?<date>.*?)<\/p>.*?<\/li>/gs;        //g 标志表示全局匹配全部符合要求的,s 标志使 . 能够匹配换行符
        const results = [...str.matchAll(reg)];

        const resultSet = results.map(result => ({
            title: result.groups.title,
            date: result.groups.date
        }));

        console.log(resultSet);

类的私有属性

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,'45kg');

console.log(girl);

Promise.allSettled和Promise.all

都是用来处理批量异步任务的场景

//创建两个Promise对象
const p1 = new Promise((resolve, reject) => {
   setTimeout(()=>{
        reject('商品1');
   });
});

const p2 = new Promise((resolve, reject) => {
    setTimeout(()=>{
        resolve('商品2');
    });
});

//批量执行异步任务
//当需要每个异步任务都能执行并得到结果就使用allSettled
const allset = Promise.allSettled([p1,p2]);
console.log(allset);

//当需要每个异步任务都能成功再往下执行,就使用all
const all = Promise.all([p1,p2]);
console.log(all);

可选链操作符

//可选链操作符  ?.
function main(config) {
    //数据属性是否传入判断
    // const dbHost = config && config.db && config.db.host;
    const dbHost = config?.db?.host;
    console.log(dbHost);
}

main({
    db:{
        host:'192.168.2.1',
        username:'root'
    },
    cache:{
        host:'192.168.2.3',
        username:'cache'
    }
})

动态import导入

按需加载(懒加载)

<body>
	<button id="btn">check</button>
</body>
    <script src="./动态import.js" type="module"></script>
//正常情况下导入
// import * as hell from "./动态import-hello.js";
const btn = document.getElementById('btn');

btn.onclick = function () {
    //import()导入结果是一个Promise对象
    import('./动态import-hello.js').then(module =>{
        module.hello();
    })
}
export function hello() {
    alert('Hello')
}

BigInt类型

// //大整型
// let n = 521n;
// console.log(n,typeof(n));       //521n 'bigint'

//函数
// let n = 123;
// console.log(BigInt(n));         //123n
// console.log(BigInt(1.2));       // The number 1.2 cannot be converted to a BigInt because it is not an integer

//大数值运算
let max = Number.MAX_SAFE_INTEGER;
// console.log(max);           //9007199254740991
// console.log(max+1);         //9007199254740992
// console.log(max+2);         //9007199254740992      不能表示更大的运算结果

console.log(BigInt(max));                   //9007199254740991n
console.log(BigInt(max)+BigInt(1));         //9007199254740992n
console.log(BigInt(max)+BigInt(2));         //9007199254740993n

globalThis对象

globalThis 是 ECMAScript 2020(ES11)引入的一个全局对象,用于在不同环境中访问全局作用域(全局对象),它提供了一个统一的方式来获取全局作用域,无论是在浏览器、Node.js 还是 Web Workers 等环境中。

为什么需要 globalThis

在不同的执行环境中,全局对象的名称不一致:

  • 浏览器window
  • Node.jsglobal
  • Web Workersself

globalThis 统一了这些差异,确保代码在不同的环境中都能访问到全局对象,不需要依赖特定的名称。

posted @ 2025-01-09 18:30  swtxx  阅读(20)  评论(0)    收藏  举报