ES6-ES11 学习笔记

概述

什么是 ECMAScript

ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际;

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

ES6新特性

1. let关键字

let 关键字用来声明变量

let a; // 单个声明 
let b,c,d; // 批量声明 
let e = 100; // 单个声明并赋值 
let f = 521, g = 'abc', h = []; // 批量声明并赋值

使用 let 声明的变量有几个特点:

不允许重复声明

let a = 1;
let a = 2;

在这里插入图片描述

块儿级作用域(局部变量)

{
	// 这里通过括号定义了局部变量,同样适用于if、else、for、while、函数等能创建局部变量的操作
    let test = "123";
    console.log(test);
}
// 在外部拿不到局部变量中定义的test
console.log(test)

在这里插入图片描述

不存在变量提升

变量提升:就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;

// 使用var创建的变量,在程序开始运行时,先通过var p1;创建变量p1,所以能打印出来undefined (即变量提升)
// 使用let创建的变量不会存在变量提升问题
console.log(p1);
console.log(p2);

var p1 = 123;
let p2 = 123;

在这里插入图片描述

不影响作用域链

// 在父级作用域创建变量p
let p = 123;
function fn() {
    // let p = 456;   如果在子级作用域重新定义了 变量p,不会影响父级作用域,并且子级作用域中引用的也是子级的变量p
    // 子级作用域引用变量p,如果自己作用域找不到就会在父级作用域中找
    console.log(p);
}
fn();

在这里插入图片描述

let应用

使用var创建变量
<div class="container">
    <h2 class="page-header">let案例:点击div更改颜色</h2>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
<script>
    let items = document.getElementsByClassName('item');
	// 使用var创建变量i
    for (var i=0; i<items.length; i++) {
        items[i].onclick = function () {
            items[i].style.background = "pink";
        }
    }
</script>

使用var创建变量i,相当于全局变量,而onclick绑定的方法相当于异步事件。由于i是全局变量,等for循环结束时i=3。点击的时候items[3]是undefined,所以会报错。
在这里插入图片描述

使用let创建变量
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>let案例:点击div更改颜色</title>
    <link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .item {
            width: 100px;
            height: 50px;
            border: solid 1px rgb(42, 156, 156);
            float: left;
            margin-right: 10px;
        }
    </style>
</head>
<body>
<div class="container">
    <h2 class="page-header">let案例:点击div更改颜色</h2>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
<script>
    let items = document.getElementsByClassName('item');
	// 使用let创建局部变量,每个变量都有自己的作用域,不会互相影响
    for (let i=0; i<items.length; i++) {
        items[i].onclick = function () {
            items[i].style.background = "pink";
        }
    }
</script>
</body>
</html>

在这里插入图片描述

2. const关键字

const 关键字用来声明常量

// const声明常量 
const DOG = "旺财";
console.log(DOG);

const 声明有以下特点:

声明必须赋初始值

在这里插入图片描述

不允许重复声明

在这里插入图片描述

值不允许修改

  1. const 关键字用于创建常量,而常量创建后就不允许修改;
    在这里插入图片描述
  2. 数组或对象等添加/删除/修改元素可以正常执行,可以理解变量指向的地址没有变化,只是内容变化了。
    在这里插入图片描述

块儿级作用域(局部变量)

{ 
    const CAT = "喵喵"; 
    console.log(CAT); 
}
console.log(CAT);

在这里插入图片描述

3. 变量和对象的结构赋值

什么是解构赋值

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

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

// 2、对象的解构赋值
const tony = {
    name: "aaa",
    age: 26,
    test: function () {
        console.log("LALALA")
    }
}
let {name, age, test} = tony; // 注意解构对象这里用的是{}
console.log(name)
console.log(age)
test(); // 此方法可以正常调用

4. 模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

字符串中可以出现换行符

以前的语法如果字符串中需要换行,只能通过 + 拼接,否则会报错。
在这里插入图片描述
ES6支持通过反引号来描述字符串:
在这里插入图片描述

可以使用 ${xxx} 形式引用变量

在这里插入图片描述

5. 简化对象和函数写法

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

const a = "我是 a";
let b = function () {
    console.log("lalala");
}

const c = {
    // a: a,  完整写法
    a,
    // b: b   完整写法
    b,
    // 声明方法的简化
    say() {
        console.log("4545445")
    }
}

6. 箭头函数

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

箭头函数定义

// ES5写法:
let a = function () {
    console.log("hello a");
}
a();

// ES6+写法 箭头函数相当于用 => 代替了 function 关键字
let b = () => {
    console.log("hello b");
}
b();

箭头函数的特点

  1. 如果形参只有一个,则小括号可以省略
// 完整写法
let b = (c) => {
    console.log("hello " + c);
}
b("haha");

// 如果形参只有一个则可以省略小括号
let c = d => {
    console.log("hello " + d);
}
c("haha");
  1. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果;
// 完整写法
let a = (n) => {
    return n * n
}
console.log(a(9));

// 一个形参省略小括号写法
let b = n => {
    return n * n
}
console.log(b(9));

// 函数只有一行语句时,省略花括号和return关键字写法
let c = n => n * n;
console.log(c(9));

// 函数只有一行语句时,省略花括号和return关键字写法;
// 多个形参不能省略小括号
let d = (n1, n2) => n1 * n2;
console.log(d(9, 10));
  1. 箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值;
// 普通函数
let a = function () {
    console.log(this.name);
}

// 箭头函数
let b = () => {
    console.log(this.name);
}

// 因为当前函数a和b都定义在全局变量中,this实际上指向的是window,所以这里给window添加name属性
window.name = "HAHAHA";

// 调用后都打印的"HAHAHA"
a();
b();

// 定义变量c
let c = {
    name: "HEIHEIHEI"
}
// 通过call方法可以改变this指向,但是箭头函数this不会改变,只会指向创建时的作用域window
a.call(c);
b.call(c);

在这里插入图片描述

  1. 箭头函数不能作为构造函数实例化;
let Person = (name, age) => {
            this.name = name;
            this.age = age;
        }

let me = new Person("aaa", 24);

在这里插入图片描述
5. 不能使用 arguments 变量:

// 普通函数可以使用arguments 变量,其中保存的是实参
let a = function (a1, a2) {
    console.log(arguments);
}
a("a", "b");

// 箭头函数不能使用arguments变量
let b = (a1, a2) => {
    console.log(arguments);
}
b("a", "b");

在这里插入图片描述

箭头函数的应用

箭头函数适合与this无关的回调,如:定时器。数组的回调方法;
箭头函数不适合与this有关的回调, 如:事件回调,对象的方法;

需求1

要求:点击div 2s后颜色变为粉色

版本1:

<body>
<div id="ad"></div>

<script>
    // 需求: 点击div 2s后变为粉色

    // 1. 根据id找到元素
    let ad = document.getElementById("ad");

    // 2. 绑定click事件
    ad.addEventListener("click", function () {

        setTimeout(function () {
            // 这里会报错
            this.style.background = "pink";
            // 打印this,发现指向的是window,而window没有style属性,所以会报错
            console.log(this);
        }, 2000);

    })
</script>
</body>

版本2:

// 1. 根据id找到元素
let ad = document.getElementById("ad");

// 2. 绑定click事件
ad.addEventListener("click", function () {
    // 这里的this指向的是div元素本身,用_this保存指向this,即指向div。
    // _this实际上是绑定到了window._this
    console.log(this);
    _this = this;

    setTimeout(function () {
        // 在setTimeout内部调用_this,会从window获取_this拿到div元素
        _this.style.background = "pink";
        console.log(this); //这里打印this是指向window的
        console.log(_this); //这里打印_this是div,属于window._this
    }, 2000);

})

版本3:箭头函数

// 1. 根据id找到元素
let ad = document.getElementById("ad");

// 2. 绑定click事件
ad.addEventListener("click", function () {

    setTimeout(() => {
        // 箭头函数this是指向创建函数时的作用域,即div元素本身
        this.style.background = "pink";
        console.log(this); //这里打印this是div元素
    }, 2000);
})
需求2

要求:从数组中返回偶数的元素

// 普通函数 
const result = arr.filter(function (item) {
    return item % 2 === 0
})
console.log(result)

// 使用箭头函数
const result1 = arr.filter(item => item % 2 === 0)
console.log(result1)

7. ES6中函数参数的默认值

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

函数设置默认值

function add(a, b, c) {
    return a + b + c;
}

// 传入3个参数,结果为 6
let result = add(1, 2, 3);
console.log(result);

// 只传入2个参数,结果为NaN
let result1 = add(1, 2);
console.log(result1);

// 定义函数时,指定参数默认值
function add1(a, b, c=10) {
    return a + b + c;
}
// 传入2个参数,第3个参数会使用默认值,结果为13
let result2 = add1(1, 2);
console.log(result2);

与解构赋值结合使用

function connect({host, username, password="123456"}) {
    console.log(host);
    console.log(username);
    console.log(password);
}

connect({
    host: "localhost",
    username: "root",
    password: "root"
})

connect({
    host: "localhost",
    username: "root"
})

8. rest参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
参考文章: https://www.jianshu.com/p/50bcb376a419

// 普通函数通过arguments能获取所有的实参,arguments是一个对象
function date(a, b) {
    console.log(arguments);
}
date("hahaha", "heiheihei");

// rest 参数, ES6中通过...args获取实参,并且...args必须放最后

function date1(a, ...args) {
    console.log(a);
    console.log(args);
}
// 注意:这里传入两个参数,"haha"会赋值给a实参; "heihei"会赋值给args,
// 也就是说剩余的参数都会付给args,args是一个数组
date1("haha", "heihei");

在这里插入图片描述

9. 扩展运算符

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

// ... 扩展运算符能将数组转换为逗号分隔的参数序列 
// 声明一个数组 ...
const tfboys = ['易烊千玺', '王源', '王俊凯'];
// => '易烊千玺','王源','王俊凯'
// 声明一个函数
function chunwan() {
    console.log(arguments);
}

chunwan(tfboys);
chunwan(...tfboys); // chunwan('易烊千玺','王源','王俊凯')

在这里插入图片描述

扩展运算符应用

    //1. 数组的合并 情圣 误杀 唐探
    const kuaizi = ['王太利', '肖央'];
    const fenghuang = ['曾毅', '玲花'];

    // 传统的合并方式
    const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
    const zuixuanxiaopingguo1 = [...kuaizi, ...fenghuang];
    console.log(zuixuanxiaopingguo);
    console.log(zuixuanxiaopingguo1);

    //2. 数组的克隆
    const sanzhihua = ['E', 'G', 'M'];
    const sanyecao = [...sanzhihua];// ['E','G','M']
    console.log(sanyecao);

    //3. 将伪数组转为真正的数组
    const divs = document.querySelectorAll('div');
    const divArr = [...divs];
    console.log(divArr);

在这里插入图片描述

10. Symbol

Symbol 概述

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

Symbol 的特点:

  1. Symbol 的值是唯一的,用来解决命名冲突的问题;
  2. Symbol 值不能与其他数据进行运算;
  3. Symbol 定义的对象属性不能使用for…in循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名;

参考文章:https://blog.csdn.net/fesfsefgs/article/details/108354248

//创建Symbol
let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('尚硅谷');

let s3 = Symbol('尚硅谷');
console.log(s2 === s3); // false

// Symbol.for 创建的symbol,如果描述符一样,那么得到的对象也一样
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');
console.log(s4 === s5); // true

// 不能与其他数据进行运算--会报错
let result = s + 100;
let result1 = s > 100;
let result2 = s + s;

// JS 7种数据类型 USONB you are so niubility
// u undefined
// s string symbol
// o object
// n null number
// b boolean

Symbol创建对象属性

    // 假如有一个很复杂的对象,需要向对象中添加方法 up down 方法,不确定是不是原来已经右up和down方法了
    let game = {
        name: '俄罗斯方块',
        up: function () {
        },
        down: function () {
        }
    };

    // 我们要往game对象里面添加方法,但是怕game对象已经存在同名方法,所以可以使用Symbol
    // 方法一:
    let methods = {
        up: Symbol(),
        down: Symbol()
    };

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

    console.log(game);
    // 调用
    game[methods.up]();
    game[methods.down]();

    // 方法二:
    let say = Symbol('say');
    let youxi1 = {
        name: "狼人杀",
        [say]: function () {
            console.log("我可以发言")
        }
    }
    // 调用
    youxi1[say]();

Symbol内置值

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

class Person {
    // 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用Symbol.hasInstance方法
    static [Symbol.hasInstance](param) {
        console.log(param);
        console.log("我被用来检测类型了");
        return false;
    }
}

let o = {};
console.log(o instanceof Person);


const arr = [1,2,3];
const arr2 = [4,5,6];
console.log(arr.concat(arr2));

// 合并数组:false数组不可展开,true可展开
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));

在这里插入图片描述

11. 迭代器

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

ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费;
原生具备 iterator 接口的数据(可用 for of 遍历),例如:Array、Arguments、Set、Map、String、TypedArray、NodeList;

工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置;
  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
  4. 每调用 next 方法返回一个包含 value 和 done 属性的对象;

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

// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];

// 使用 for...of 遍历数组, 得到的是数组中的元素本身
for (let v of xiyou) {
    console.log(v);
}

// 使用 for...in 遍历数组, 得到的是数组中元素的下标
for (let i in xiyou) {
    console.log(i);
}

// 初始化迭代器对象
let iterator = xiyou[Symbol.iterator]();

console.log(iterator);   // Array Iterator 对象,迭代器的next方法指向下一个元素,类似于链表解构。

// 通过调用迭代器的next方法获取下一个元素。 返回对象中value字段代表值,done代表是否还有元素没有遍历。
console.log(iterator.next());       // {value: "唐僧", done: false}
console.log(iterator.next());       // {value: "孙悟空", done: false}
console.log(iterator.next());       // {value: "猪八戒", done: false}
console.log(iterator.next());       // {value: "沙僧", done: false}

// 遍历完成后,再调用next方法,done字段为true,代表已经遍历完成
console.log(iterator.next());       // {value: undefined, done: true}

在这里插入图片描述

自定义迭代器遍历对象

    // 要求遍历banji对象stus数组
    const banji = {
        name: "终极一班",
        stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
        // 自定义迭代器
        [Symbol.iterator]() {
            let index = 0;
            return {
                next: () => {
                    // console.log(this);
                    if (index < this.stus.length) {
                        const result = {
                            value: this.stus[index],
                            done: false
                        };
                        index++;
                        return result
                    } else {
                        return {
                            value: undefined,
                            done: true
                        }
                    }
                }
            }
        }
    }

    // 注意:for..of 遍历出来的是value值,而不是{value: xxx, done: ture/false}
    for (let v of banji) {
        console.log(v)
    }

在这里插入图片描述

12. 生成器

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

    // 生成器其实就是一个特殊的函数
    // 异步编程 纯回调函数 node、fs、ajax等

    // 1. 定义生成器函数
    function * gen () {
        console.log(111);
        // 函数会执行到yield时停下来不再向下执行,直到下一次再调用next方法,从下一行开始继续执行,直到遇到下一个yield
        // yield后面的值作为返回值
        yield '一只没有耳朵';

        console.log(222);
        yield '一只没有尾部';

        console.log(333);
        yield '真奇怪';

        console.log(444);
    }
    // 2. 生成器执行
    // 2.1 生成器函数返回的是迭代器对象,因此可以通过next方法遍历
    let g = gen();
    console.log(g);

    console.log(g.next());
    console.log(g.next());
    console.log(g.next());
    console.log(g.next());

    // 2.2 用for..of 也可以执行生成器对象
    for (let v of gen()) {
        console.log(v);
    }

在这里插入图片描述

生成器函数的参数传递

    function * gen (arg) {
        console.log(arg);

        let one = yield '一只没有耳朵';

        console.log(one);
        let two = yield '一只没有尾部';

        console.log(two);
        let three = yield '真奇怪';

        console.log(three);
    }

    let g = gen("A");
    console.log(g);

    console.log(g.next());     // 打印 A, {value: '一只没有耳朵', done: false}
    // 传入的参数"B",传给了 one
    // 上一次调用next,执行到了 let one = yield '一只没有耳朵'; 等号右侧结束,
    // 这一次再调用next("B"),即 let one = "B";
    console.log(g.next("B"));  // 打印 B, {value: '一只没有尾部', done: false}
    console.log(g.next("C"));  // 打印 C, {value: '真奇怪', done: false}
    console.log(g.next("D"));  // 打印 D, {value: undefined, done: true}

在这里插入图片描述

生成器应用

    // 异步编程 文件操作 网络操作(ajax,request) 数据库操作
    // 需求:1s后控制台输出111 再过2s后控制台输出222 再过3s后控制台输出333
    //
    // 方案一:回调地狱 ,嵌套很多层
    setTimeout(() => {
        console.log(111);
        setTimeout(() => {
            console.log(222);
            setTimeout(() => {
                console.log(333);
            }, 3000)
        }, 2000)
    }, 1000)

    // 方案二:生成器
    function one() {
        setTimeout(() => {
            console.log(111);
            iterator.next();
        }, 1000)
    }

    function two() {
        setTimeout(() => {
            console.log(222);
            iterator.next();
        }, 1000)
    }

    function three() {
        setTimeout(() => {
            console.log(333);
            iterator.next();
        }, 1000)
    }

    function * gen() {
        yield one();
        yield two();
        yield three();
    }
    // 调用生成器函数
    let iterator = gen();
    iterator.next();
    // 模拟获取: 用户数据 订单数据 商品数据
    function getUsers() {
        setTimeout(() => {
            let data = "用户数据"; // 第二次调用next,传入参数,作为第一个的返回值
            iterator.next(data); // 这里将data传入赋值给gen中的users
        }, 1000);
    }

    function getOrders() {
        setTimeout(() => {
            let data = "订单数据";
            iterator.next(data); // 这里将data传入赋值给gen中的orders
        }, 1000);
    }

    function getGoods() {
        setTimeout(() => {
            let data = "商品数据";
            iterator.next(data); // 这里将data传入赋值给gen中的goods
        }, 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();

在这里插入图片描述

13.Promise

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

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

基本用法

    let p = new Promise(function (resolve, reject) {
        setTimeout(function () {
            // 获取成功--调用resolve并传入获取的数据--> p.then的第一个参数进行处理
            let data = "success";
            resolve(data);

            // 获取失败--调用reject并传入错误信息--> p.then的第二个参数进行处理
            // let err = "failed";
            // reject(err);
        }, 2000)
    });

    // 通过p.then 处理成功和失败的逻辑
    // then方法的两个参数都是函数,分别代表获取成功和获取失败的逻辑
    p.then(function (data) {
        console.log("获取成功" + data);
    }, function (err) {
        console.log("获取失败" + err);
    })

在这里插入图片描述

Promise封装Ajax请求

    // 请求地址:https://api.apiopen.top/getJoke
    let p = new Promise(function (resolve, reject) {
        // 原生请求
        // 1. 创建对象
        const xhr = new XMLHttpRequest();
        // 2、初始化
        xhr.open("GET","https://api.apiopen.top/getJoke");
        // 3、发送
        xhr.send();

        // 4、绑定事件,处理响应结果
        xhr.onreadystatechange = function () {
            // 判断状态
            if (xhr.readyState === 4) { // 判断响应状态码 200-299
                if (xhr.status >= 200 && xhr.status <= 299) {
                    // 成功
                    resolve(xhr.response);
                } else {
                    // 失败
                    reject(xhr.status);
                }
            }
        }
    });
    
    p.then(function (data) {
        console.log("获取成功" + data.toString());
    }, function (err) {
        console.log("获取失败" + err);
    })

promise链式调用

    let p = new Promise((resolve, reject) => {

        setTimeout(() => {
           resolve("用户数据");
        }, 1000);
    })

    const result = p.then(data => {
        // console.log(data);
    }, err => {
        console.error(err);
    });

    // 打印result可以到到result也是promise类型,因此then方法可以链式调用
    console.log(result);

    p.then(data => {
        console.log(data)
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("订单数据");
            }, 2000);
        })
    }).then(data => {
        console.log(data)
    })

在这里插入图片描述

Promise对象catch方法

    let p = new Promise((resolve, reject) => {

        setTimeout(() => {
           resolve("用户数据");
        }, 1000);
    })

    // then方法的两个参数也可以只写一个,例如:只处理成功的情况
    p.then(data => {
        console.log(data)
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject("获取订单失败");
            }, 2000);
        })
    }).then(data => {
        console.log(data)
    }).catch(err => {
        // catch方法用于捕获reject时的错误,特别是多个then链式调用时,
        // then只处理resolve的情况,再catch中处理reject的情况
        console.log(err)
    })

在这里插入图片描述

14. Set集合

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

集合的属性和方法:

  1. size 返回集合的元素个数;
  2. add 增加一个新元素,返回当前集合;
  3. delete 删除元素,返回 boolean 值;
  4. has 检测集合中是否包含某个元素,返回 boolean 值;
  5. clear 清空集合,返回 undefined;
    // Set集合
    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. clear 清空集合,返回 undefined;
    s1.clear();
    console.log(s1);

在这里插入图片描述

集合的应用

    // Set集合实践
    let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    // 数组去重
    let s1 = new Set(arr);
    console.log(s1);

    // 去重后求交集
    let arr2 = [3, 4, 5, 6, 5, 4, 3];
    let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
    console.log(result);

    // 去重后求并集
    // ... 为扩展运算符,将数组转化为逗号分隔的序列
    let union = [...new Set([...arr, ...arr2])];
    console.log(union);

    // 去重后差集:比如集合1和集合2求差集,就是1里面有的,2里面没的
    let result1 = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
    console.log(result1);

在这里插入图片描述

15. Map集合

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

Map 的属性和方法:

  1. size 返回 Map 的元素个数;
  2. set 增加一个新元素,返回当前 Map;
  3. get 返回键名对象的键值;
  4. has 检测 Map 中是否包含某个元素,返回 boolean 值;
  5. clear 清空集合,返回 undefined;
    // 创建一个空 map
    let m = new Map();
    // 创建一个非空 map
    let m2 = new Map([['name', '尚硅谷'], ['slogon', '不断提高行业标准']]);
    // 1. size 返回 Map 的元素个数;
    console.log(m2.size);

    // 2. set 增加一个新元素,返回当前 Map;
    m.set("皇帝", "大哥");
    m.set("丞相", "二哥");
    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);

在这里插入图片描述

16. class类

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

class初体验

    // 1. ES5写法 实现类
    function Phone(brand, price) {
        this.brand = brand;
        this.price = price;
    }

    // 添加方法
    Phone.prototype.call = function () {
        console.log("Phone 我可以打电话!");
    }

    // 实例化对象
    let HuaWei = new Phone("华为", 5999);
    HuaWei.call();
    console.log(HuaWei);


    // 2. ES6语法实现类
    class Phone1{
        // 构造方法
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }
        
        call() {
            console.log("Phone1 我可以打电话!");
        }
    }
    // 实例化对象
    let xiaomi = new Phone1("小米", 3999);
    xiaomi.call();
    console.log(xiaomi);

在这里插入图片描述

class静态成员

    // class静态成员
    // 1. ES5写法
    function Phone() {
    }

    // 这里是构造函数对象添加属性和方法,是静态属性/方法,只能通过“ 类名.属性/方法 ”调用,不能通过实例化的对象调用
    Phone.name = "手机";
    Phone.change = function () {
        console.log("我可以改变世界!");
    }

    // 实例化对象
    let nokia = new Phone();
    console.log(nokia.name); // 报:undefined,name属性是静态属于,是属于类对象本身的,不属于实例化对象的
    nokia.change(); // 报错:Uncaught TypeError: nokia.change is not a function

    // 在构造函数原型对象上添加color属性,实例化后的对象可以拿到color属性
    Phone.prototype.color = "黑色";
    console.log(nokia.color); // 黑色
    console.log(Phone.name);


    // 静态属性和方法要通过 “ 类名.属性/方法 ” 调用
    Phone.change();


    // 2. ES6 写法
    class Phone1 {
        // 通过static关键字定义静态属性
        static name = "手机";

        static change() {
            console.log("我可以改变世界!");
        }
    }

    let xiaomi = new Phone1();
    console.log(xiaomi.name);  // undefined
    console.log(Phone1.name);  // 手机
    Phone1.change();

继承和多态

    // 1. ES5构造函数继承
    // 手机
    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();


    // 2. ES6 写法
    class Phone1 {
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }

        call() {
            console.log("我可以打电话!");
        }
    }

    class SmartPhone1 extends Phone1 {
        // 构造函数
        constructor(brand, price, color, size) {
            // 调用父类构造函数
            super(brand, price);

            this.color = color;
            this.size = size;
        }

        photo() {
            console.log("我可以拍照!");
        }

        game() {
            console.log("我可以玩游戏!");
        }

        // 重写父类的call方法
        call() {
            super.call();
            console.log("我是子类的call方法")
        }
    }

    const chuizi1 = new SmartPhone1("小米", 1999, "黑色", "5.15inch");
    console.log(chuizi1);
    chuizi1.call();
    chuizi1.photo();
    chuizi1.game();

class中的getter和setter设置

    class Phone {
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }

        get getPrice() {
            return this.price
        }

        set setPrice(price) {
            // 这里可以加一些对price的校验
            this.price = price
        }
    }

    let p = new Phone("xiaomi", 4444);
    console.log(p.price);
    p.price = 5555;
    console.log(p.price);

在这里插入图片描述

17. 数值扩展

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

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

  3. Number.isFinite() 与 Number.isNaN() :

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

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

  6. Number.parseInt() 与 Number.parseFloat():ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;

  7. Math.trunc:用于去除一个数的小数部分,返回整数部分;

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

    // 数值扩展
    // 0. Number.EPSILON 是 JavaScript 表示的最小精度 // EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
    function equal(a, b) {
        return Math.abs(a - b) < Number.EPSILON;
    }

    console.log("0、Number.EPSILON 是 JavaScript 表示的最小精度");
    // 箭头函数简化写法
    equal = (a, b) => Math.abs(a - b) < Number.EPSILON;
    console.log(0.1 + 0.2);
    console.log(0.1 + 0.2 === 0.3); // false
    console.log(equal(0.1 + 0.2, 0.3)); // true

    // 1. 二进制和八进制
    console.log("1、二进制和八进制");
    let b = 0b1010;
    let o = 0o777;
    let d = 100;
    let x = 0xff;
    console.log(x);

    // 2. Number.isFinite 检测一个数值是否为有限数
    console.log("2、Number.isFinite 检测一个数值是否为有限数");
    console.log(Number.isFinite(100));
    console.log(Number.isFinite(100 / 0));
    console.log(Number.isFinite(Infinity));

    // 3. Number.isNaN 检测一个数值是否为 NaN
    console.log("3. Number.isNaN 检测一个数值是否为 NaN");
    console.log(Number.isNaN(123));

    // 4. Number.parseInt Number.parseFloat字符串转整数
    console.log("4. Number.parseInt Number.parseFloat字符串转整数");
    console.log(Number.parseInt('5211314love'));
    console.log(Number.parseFloat('3.1415926神奇'));

    // 5. Number.isInteger 判断一个数是否为整数
    console.log("5. Number.isInteger 判断一个数是否为整数");
    console.log(Number.isInteger(5));
    console.log(Number.isInteger(2.5));

    // 6. Math.trunc 将数字的小数部分抹掉
    console.log("6. Math.trunc 将数字的小数部分抹掉 ");
    console.log(Math.trunc(3.5));

在这里插入图片描述

18.对象扩展

ES6 新增了一些 Object 对象的方法:

  1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
  2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象;
  3. proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型;
    // 对象扩展
    // 1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
    console.log(Object.is(120,120)); // ===

    // 注意下面的区别
    console.log(Object.is(NaN,NaN));
    console.log(NaN === NaN); // NaN与任何数值做===比较都是false,跟他自己也如此!

    // 2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象;
    const config1 = {
        host: "localhost",
        port: 3306,
        name: "root",
        pass: "root",
        test: "test" // 唯一存在
    }
    const config2 = {
        host: "http://zibo.com",
        port: 300300600,
        name: "root4444",
        pass: "root4444",
        test2: "test2"
    }

    // 如果前边有后边没有会添加,如果前后都有,后面的会覆盖前面的
    console.log(Object.assign(config1,config2));

    // 3. __proto__、setPrototypeOf、 getPrototypeOf 可以直接设置对象的原型;
    const school = {name: "尚硅谷"}
    const cities = {xiaoqu: ['北京', '上海', '深圳']}
    // 并不建议这么做
    Object.setPrototypeOf(school, cities);
    console.log(Object.getPrototypeOf(school));
    console.log(school);

在这里插入图片描述

19.模块化

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

模块化的好处

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

  1. 防止命名冲突;
  2. 代码复用;
  3. 高维护性;

模块化规范产品

ES6 之前的模块化规范有:

  1. CommonJS => NodeJS、Browserify;
  2. AMD => requireJS;
  3. CMD => seaJS;

ES6 模块化语法

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

  1. export 命令用于规定模块的对外接口(导出模块);
  2. import 命令用于输入其他模块提供的功能(导入模块);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值