• ES6+知识点总结


    ES6+知识点总结


    前言

    本文主要介绍的是ES6以及更新的JavaScript脚本语言标准规范的使用。主要是对相关知识点的自我认知和理解,如有不对的地方,望指出并探讨

    一、变量的声明

    1.let关键字

    通过let关键字声明变量

    let dzw = "大张伟";
    
    • 1

    let关键字声明的变量的特点:

    • 没有声明提前(无建立阶段),不存在变量提升
    • 有区域性,形成块级作用域
    • 自动形成闭包
    • 同一个作用域内,不能定义重复变量
    • 不影响作用域链
    • 存在暂时性死区:不能在声明之前,使用该变量(使用let声明的变量名,在let声明之前的使用,都是暂时性死区)
    • 不会挂载到全局对象
    • 相对const而言,let可以不用必须赋初始值

    var关键字声明的变量特点

    • 声明提前(有建立阶段),存在变量提升,(即是定义之前可以使用)
    • 没有区域性,无法形成块级作用域
    • 可以重估声明变量
    • window环境下,使用var,会将该变量挂载到window对象上

    1.let经典应用理解

    • 循环中使用异步函数

    var关键字

    for (var i = 1; i <= 10; i++) {
        console.log(i, "outer"); // 1 - 10
        setTimeout(function () {
            console.log(i, "inner"); // 10 个 11
        }, i * 500);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分析:

    var i = 1,首先是不会形成局部作用域的,而且会将i变量的声明提升至for循环体的外面,这里会挂载到window对象下,同步逻辑代码for循环执行完后 ,再执行 setTimeout异步代码,此时在setTimeout异步里面,存在变量i,但没有声明,所以会向父级作用域链查找,找到了window.i = 10++; 所以会打印10个11

    使用IIFE,立即执行函数解决这个问题

    for (var i = 1; i <= 10; i++) {
        setTimeout((function (j) {
            return function() {
                console.log(j);
            }
        })(i), i * 500);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    分析:

    这里会把每次循环的变量i,传到setTimeout的回调函数里,使用闭包的方式,进行变量的保存,当然会存在闭包的缺点,比如变量无法销毁,导致内存的泄露

    使用let关键字解决这个问题

    for (let i = 1; i <= 10; i++) {
        console.log(i, "outer"); // 1 - 10
        setTimeout(function () {
            console.log(i, "inner"); // 1-10
        }, i * 500);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分析:

    let i = 1; 不存在变量声明提升,而且会形成局部作用域{},将当前循环的变量保存到当前的作用域下;每次迭代都形成一个具有新的初始化let i的局部作用域,且每个let i 互不影响。之后的每一个初始化的i值,都是上一次迭代的i的结果,因此在同步for代码执行完后,再执行setTimeout,会在当前局部作用域下,找到之前保存的初始化的i变量值。 因为变量i的持久保存(遇到每个作用域的 } ,let销毁,作用域销毁),所以let会自动形成闭包

    二、常量的声明

    1.const关键字

    通过const关键字声明常量

    const DZW = "大张伟";
    
    • 1

    const定义的常量的特点:

    • 有区域性,会形成局部作用域/ 块级作用于
    • 常量的栈值不能修改 【只能锁住基本数据类型】
    • 无建立阶段,(不存在声明提前)
    • 必须赋初始值,(与let的不同)
    • 锁栈不锁堆,(基本类型不能更改,但是引用类型的属性还是可以更改的`
    • 常量名一般的 需要全部大写

    锁栈不锁堆的扩展:

    使用Object.freeze(obj); 可以锁住对象(锁堆)

    const DZW = {
    	age : 18
    };
    Object.freeze(DZW);
    DZW.age = 35;  // DZW 这个对象被冻结,其内部属性更改失败
    console.log(DAW.age) // 18
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三、扩展运算符:…

    … 扩展运算符将数组转化为 逗号分隔的实参参数序列: test(…arr)

    应用一:使用扩展运算符实现数组的合并

    let xing = ["大"];
    let ming = ["张伟"];
    let dzw = [...xing, ...ming]; // ["大","张伟"]
    
    • 1
    • 2
    • 3

    应用二:数组克隆: 浅拷贝

    let dzw = ["大","张伟"]; 
    let _dzw = [...dzw];
    console.log(_dzw);
    
    • 1
    • 2
    • 3

    应用三:类数组转数组

    function add() {
        // 类数组 Array.isArray(arguments)
        console.log(arguments, Array.isArray(arguments)); // [Arguments] { '0': 1, '1': 2, '2': 3 } false
        let _argu = [...arguments];
        console.log(_argu, Array.isArray(_argu));  // [ 1, 2, 3 ] true
    }
    add(1, 2, 3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    应用三:求数组中的最大值

    var arr = [1,3,5,7,2,9,8];
    // var max = Math.max(1, 3, 5, 7, 2, 9, 8);
    // var max = Math.max.apply(Math,arr);   //apply所接收的参数是一个数组
    var max = Math.max(...arr);
    
    • 1
    • 2
    • 3
    • 4

    四、解构赋值

    1、数组的解构赋值

    let arr = ['篮球', 'music'];
    let [ball, other] = arr; // ball = '篮球' other = 'music'
    
    • 1
    • 2

    2、对象的解构赋值

    let zhw = {
    	name: 'zhw'
    	age: 18,
    	say(){
    	 console.log('hello')
    	}
    }
    let { say } = zhw;
    say()  // 'hello’
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    五、模板字符串

    模板字符串使用 `` 反引号

    特性:

    • 字符串内容可以直接换行
    • 可以使用${}拼接变量

    六、箭头函数

    const test = (a, b) => {
    	return a + b
    }
    const sum = test(1, 2)
    console.log(sum) // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    特性:

    • this是静态的。 this始终指向函数声明时, 所在作用域下的this。即箭头函数的this指向箭头函数的外层。静态的是指: call、apply、bind不能改变箭头函数的this指向
    • 不能作为构造函数实例化对象【无构造器】
    • 不能使用保存实参的 arguments 变量
    • 简写:形参有且只有一个,省略形参的() ; 代码体只有一条语句,省略代码体的{} 和return 关键字

    使用场景:箭头函数适合与this无关的回调,比如

    • 定时器
    • 数组的方法回调

    不适用场景:箭头函数不适合与this有关的回调,比如

    • DOM等事件回调 【dom事件如果使用箭头函数,那么this指向的不再是DOM事件源】
    • 对象的方法

    七、rest参数【ES6只针对数组,ES9中rest和…可以处理对象了】

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

    1. es5中收集实参

    function test() {
    	// arguments收集到的实参是一个包裹了1, 2, 3, 4, 5的类数组,本质是一个对象
    	console.log(arguments)
    }
    test(1, 2, 3, 4, 5)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以通过以下方法将类数组arguments 转化为数组

    • const array = Array.from(arguments);
    • const array = Array.prototype.slice.call(arguments)
    • const array = […arguments];

    2. es6中收集实参

    function test(...args) {
    	// 收集的实参args是一个数组
    	console.log(args);
    }
    
    • 1
    • 2
    • 3
    • 4

    注意:rest参数必须放在所有形参的最后, 否则会报语法错误

    function test(a, b, ...args) {
    	console.log(a);  // 1
    	console.log(b);  // 2
    	// 收集的实参args是一个数组
    	console.log(args);  // [3, 4, 5]
    }
    test(1, 2, 3, 4, 5)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、ES9:rest参数和…针对对象

    function test(a, b, {...args}) {
        console.log(a);  // 1
        console.log(b);  // 2
        // 收集的实参args是一个数组
        console.log(args);  // [3, 4, 5]
    }
    test(1, 2, {name: 'zhw'})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    八、Symbol

    一种新的基本数据类型

    1. 特点

    • Symbol的值是唯一的,且不可见。
    • Symbol的值不能与其他数据进行运算
    • Symbol定义的对象属性不能使用for…in,但可以使用Reflect.ownKeys获取所有键名

    2. symbol类型的数据创建

    let s = Symbol();
    // let s2 = Symbol('当前symbol的描述信息')
    let s2 = Symbol('desc')
    let s3 = Symbol('desc')
    console.log(s2 === s3) // false
    
    // 对象方法创建symbol类型
    let s4 = Symbol.for('desc')
    let s5 = Symbol.for('desc')
    console.log(s4 === s5) // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. symbol类型数据的作用:

    用来解决命名冲突的问题,

    4. 应用

    给对象添加属性和方法, 避免别人覆盖属性

    痛点:

    // 假设这是别人写的对象, 我们并不知道对象里具体有哪些属性
    let zhw = {
    	name: '呵呵'
    }
    
    // 需要给对象zhw添加name属性
    zhw.name = xxx   // 这样给对象添加属性是不安全的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决: 使用Symbol()定义需要添加的属性

    let needAddProps = {
    	name: Symbol()
    }
    
    // 这样使用不会破坏原对象的数据结构
    zhw[needAddProps.name] = xxx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    其他方法向对象添加Symbol类型的属性

    let zhw = {
    	name: '呵呵',
    	[Symbol('say')]: function() {
    		console.log('hello')
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5. Symbol的内置属性

    Symbol有自己的一些内置属性, 这些属性都是用来控制 对象在特定情况下的表现, 例如

    Sysbol.isConcatSpreadable 控制数组是否可以展开

    let arr = [1, 2, 3]
    let arr2 = [4, 5, 6]
    console.log(arr.concat(arr2)) // [1, 2, 3, 4, 5, 6]
    
    // 禁止arr2数组展开
    arr2[Sysbol.isConcatSpreadable] = false
    console.log(arr.concat(arr2)) // [1, 2, 3, [4, 5, 6]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6、description: 获取Symbol的描述信息

    let s = Symbol('zhw')
    console.log(s.description);
    
    • 1
    • 2

    九、迭代器

    迭代器(Iterator)是一种接口,为不同的数据结构提供统一的访问机制。
    js中,迭代器的本质是 对象属性

    1、原生js具备Iterator接口的数据

    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList

    注意:只要部署了Iterator接口,就可以使用ES6提供的for…of命令遍历

    2、迭代器的工作原理

    • 创建了一个指针对象iterator,指向了数据结构的起始位置 【let iterator = objSymbol.iterator
    • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员 【iterator.next()】
    • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    • 每次调用next方法,都会返回一个包含value和done属性的对象

    3、迭代器的应用:自定义遍历数据

    let zhw = {
    	name: '呵呵'
    	hobbies: [
    		'篮球',
    		'rap'
    	]
    }
    // 报错: zhw对象无iterator
    for(let item of zhw) {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    给对象加入迭代器

    let zhw = {
    	name: '呵呵'
    	hobbies: [
    		'篮球',
    		'rap'
    	],
    	[Symbol.iterator]() {
    		let index = 0
    		// 返回一个指针对象
    		return {
    			next: () => {
    				if(index < this.hobbies.length) {
    					const result = {value: this.hobbies[index], done: false)
    					index++
    					return result
    				} else {
    					return {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

    十、生成器: ES6的异步编程解决方案1

    生成器本质是一个函数。 生成器的返回结果其实是一个迭代器对象,因为具有next方法

    1、作用

    • 一种异步编程的解决方法: 解决原生js的纯回调函数,造成的回调地狱问题

    2、语法

    • 迭代器函数的声明
    // * 位置可左可右可中间
    function * gen() {
    	console.log('hello')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 迭代器函数的调用
    let iterator = gen();
    // 迭代器函数的调用语句,执行生成器函数体的语句
    iterator.next()  // 返回结果是yield对应的值
    
    • 1
    • 2
    • 3

    3、yield 生成器函数代码体的分隔符

    n个yield,将代码体分割成n + 1块

    function * gen() {
        console.log(111)
        yield '分隔符1';
        console.log(222)
        yield '分隔符2';
        console.log(333)
        yield '分隔符3';
        console.log(444)
    }
    for (const iterator of gen()) {
        console.log(iterator);
        console.log('======')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    4、生成器函数的参数

    • 生成器函数的参数
    function * gen(arg) {
        console.log(arg)
    }
    let iterator = gen('生成器函数的参数')
    iterator.next()  // 执行了 console.log(arg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 生成器返回的迭代器对象的next方法参数

    第n个yield的返回值,保存着第n + 1个的next方法参数

    function * gen() {
       console.log('代码块1')
       let one = yield 111;
       console.log(one, 'zhw');
       console.log('代码块2')
    }
    let iterator = gen()
    iterator.next()
    iterator.next('第2个next的参数')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    next传多个参数 用数组: Generator.next(…args: [] | [unknown]): IteratorResult

    function * gen() {
       console.log('代码块1')
       let one = yield 111;
       console.log(one);
       console.log('代码块2')
    }
    let iterator = gen()
    iterator.next()
    iterator.next(['第2个next的参数', 'zhw'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    5、生成器函数的应用:

    例如: 1s后打印111,2秒后打印222, 3秒后打印333

    • 原生js的实现
     setTimeout(function(){
       console.log(111)
        setTimeout(function(){
            console.log(222)
            setTimeout(function(){
                console.log(333)
            }, 3000)
        }, 2000)
    }, 1000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    缺点:多层回调嵌套造成了 地狱回调【一种回调现象】,不便于阅读和维护代码

    • 生成器解决回调地狱问题
    function one(timer, num) {
      setTimeout(() => {
        console.log(num);
        // 第二次调用next  可以通过第一个yield获取参数数据
        iterator.next('one')
      }, timer);
    }
    function two(timer, num) {
      setTimeout(() => {
        console.log(num);
        // 第三次next  此时会调用: yield three(3000, 333)
        // 不过第三次的next参数 是传递给第二个yield的返回值的
        iterator.next('two')
      }, timer);
    }
    function three(timer, num) {
      setTimeout(() => {
        console.log(num);
        iterator.next('three')
      }, timer);
    }
    
    function * gen() {
      let resOne = yield one(1000, 111);
      console.log(resOne);
      let resTwo = yield two(2000, 222);
      // 第三次yield的参数
      console.log(resTwo);
      const resThree = yield three(3000, 333);
      console.log(resThree);
    }
    
    let iterator = gen()
    // 第一次调用next
    iterator.next()
    
    • 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

    十一、Promise: ES6的异步编程解决方案2

    Promise本质是一个构造函数。 是ES6引入的异步编程的一种解决方案,主要是用来解决原生js造成的回调地狱现象

    1、基本语法

    let p = new Promise((resolve, reject) => {
       setTimeout(() => {
            resolve('111')
            // reject('err')
        }, 500)
    })
    p.then((res)=>{
        console.log(res); // 111
    }, (err)=>{
        console.log(err); // err
    })
    p,catch(err=>{
    	console.log(err); // err
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    p.then(成功的回到, 失败的回调)

    2、关于then的返回值

    p.then()的返回值始终是一个Promise。具体状态(PromiseState),由回调参数的返回值决定,规则如下

    • 1、没有return(即是返回undefined) / 返回非Promise的值 状态为:fulfilled
    • 2、return返回Promise对象: 状态和返回的Promise状态保持一致
    let p = new Promise((resolve, reject) => {
       setTimeout(() => {
            // resolve('111')
            reject('err')
        }, 500)
    })
    // p.then()的返回值始终是一个Promise。具体状态(PromiseState),由回调参数的返回值决定,规则如下
    // 1、没有return(即是返回undefined) / 返回非Promise的值  状态为:fulfilled
    // 2、return返回Promise对象: 状态和返回的Promise状态保持一致
    let res = p.then((res)=>{
        console.log(res); // 111
        // resolve('111') 触发return
    }, (err)=>{
        console.log(err); // err
        // reject('err') 触发return
        return new Promise((resolve, reject) => {
            resolve('res')
        })
    })
    console.log(res, 'res'); // PromiseState: fulfilled, PromiseResult: 'eee'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3、解决异步回调

    需求: 1s后打印111,2秒后打印222, 3秒后打印333

    • 通过then方法的链式语法
    let p = new Promise((resolve, reject) => {
       setTimeout(() => {
           resolve(111);
       }, 1000)
    })
    p.then((res)=>{  // 这个res是p对象的Promise的执行结果
       console.log(res);
       return new Promise((resolve, reject) => {
           setTimeout(()=>{
               resolve(222)
           }, 2000)
       })
    }).then(res=>{  // 这个res是上一个回调参数的 promise执行结果
       console.log(res);
       return new Promise((resolve, reject) => {
           setTimeout(()=>{
               resolve(333)
           }, 3000)
       })
    }).then(res => { // 这个res是上一个回调参数的 promise执行结果
       console.log(res);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4、处理Promise对象数组

    • Promise.allSettled: 每个Promise都能得到结果时
    const p1 = new Promise((resolve, reject) => {
       setTimeout(() => {
         resolve('111')
       }, 1000)
     })
    
     const p2 = new Promise((resolve, reject) => {
       setTimeout(() => {
         reject('222')
       }, 2000)
     })
     // PromiseState: 始终是fulfilled
     // PromiseResult[]: 
     // [{status: 'fulfilled', reason: '111'} , {status: 'rejected', reason: '111'}]
     const res = Promise.allSettled([p1, p2])
     console.log(res);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • Promise.all: 每个Promise都能得到resolve结果时, 如果一个是resolve,另一个是reject,则是在pending中;如果两个都是reject,则结果状态时rejected,值是第一个Promise元素的值
    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('111')
      }, 1000)    
    }) 
    
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('222')
      }, 2000)    
    })    
    // PromiseState: fulfilled
    // PromiseResult[]: 
    // ['111', '222']
    const res = Promise.all([p1, p2])
    console.log(res);  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ES8之async和 await: 【第三种异步解决方案】

    async 和 await 结合可以让异步代码 像同步一样执行

    1、async函数

    • async函数的返回值为promise对象, 返回值promise的具体状态,如下:
    async function fn() {
        // 1. 返回 非 Promise对象时, fn()的返回状态为: fulfilled
        // return 'zhw'
        
        // 2. 抛出一个错误时, fn()的返回状态为: rejected
        // throw new Error('error')
    
        // 3. 返回一个Promise对象时, fn()的返回状态 由 return 的 Promise状态决定
        return new Promise((resolve, reject) => {
            // resolve('data')
            reject('error')
        })
    }
    // res为一个Promise对象, 所以可以使用then()
    let res = fn()
    console.log(res);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • async函数可以没有await 表达式

    2、await 表达式

    • await 必须写在async函数中
    • await 右侧的表达式一般为 promise对象
    • await始终返回promise成功的值
    • await的promise失败了, 需要使用try…catch 捕获处理异常

    3、第三种异步解决案例,【async + await】

    1s后打印111,2秒后打印222, 3秒后打印333

    function one() {
       return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(111);
            }, 1000)
        })
    }
    function two() {
       return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(222);
            }, 2000)
        })
    }
    function three() {
       return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(333);
            }, 3000)
        })
    }
    
    async function test() {
       let _one = await one();
       console.log(_one)
       let _two = await two();
       console.log(_two)
       let _three = await three();
       console.log(_three)
    }
    test()
    
    • 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

    十二、Set集合

    集合:ES6提供的一种数据集合。类似于数组,但不是数组。本质是一个对象【typeof new Set === ‘object’】。成员都是唯一的。Set实现了迭代器接口,所以可以使用扩展运算符…和for…of

    1、Set集合对象的属性和方法

    • size: 集合元素的个数
    • add() 增加一个新元素,返回当前集合
    • delete() 删除元素 返回boolean值
    • has() 检测集合中是否包含某个元素, 返回boolean
    • clear() 清空当前集合对象
    let arr = [1, 2, 3, 4, 2, 1]
    let s = new Set(arr)
    console.log(typeof s);  // 'object'
    console.log(s.size);  // Set对象个数
    // let s2 = s.add(5)
    // console.log(s === s2);  // true: Set(5) {1, 2, 3, 4, 5}
    // let flag = s.delete(1)
    // console.log(s); // Set(5) {2, 3, 4}
    
    console.log(s.has(1));
    s.clear()
    console.log(s);
    
    
    let arr = [1, 2, 3, 4, 2, 1]
    let s = new Set(arr)
    for (const item of s) {
        console.log(item);  // 1, 2, 3, 4
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2、Set集合的应用

    • 数组去重
    let arr = [1, 2, 3, 4, 2, 1]
    let s = new Set(arr)  // 类数组 Set自带去重
    let sArr = [...s]  // 类数组转数组
    console.log(sArr);
    
    • 1
    • 2
    • 3
    • 4

    十三、Map

    ES6提供的新的数据结构。Map数据结构是一种用于存储键值对的数据结构,是一种升级版的对象,即对象的key不限于字符串,key可以是各种类型,Map中的键是唯一的。实现了迭代器接口,可以用扩展运算符…和for…of进行遍历

    1、Map的属性和方法

    • size: 返回Map的元素个数
    • set: 新增一个新的元素,放回当前Map
    • get: 根据键名获取键值
    • has: 检测Map是否包含某个元素
    • clear: 清空集合, 返回undefined
    let obj = {name: 'zhw'}
    let m = new Map()
    m.set('name', 'zhw')
    m.set('age', 18) // 被覆盖
    m.set('age', 22) // Map的键是唯一的  下面会覆盖上面的
    m.set('say', () => {console.log('i say');})
    m.set(obj, 'zhw?')
    // console.log(m); // 0: {"name" => "zhw"}
    // for (const item of m) {
    //     //  每一项是一个数组[key, value] 
    //     console.log(item);  // ['name', 'zhw']
    // }
    
    let arr = [...m]
    console.log(arr); // [Array(2), Array(2), Array(2)]   ['name', 'zhw']
    
    console.log(m.get('name'));
    console.log(m.get(obj));
    console.log(m.has('age'))
    // m.clear()
    console.log(m.clear()) // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2、Map转对象

    //  二维数组 转对象
    const result = Object.fromEntries([
      ['name', 'zhw'],
      ['age', 18]
     ])
     console.log(result);
    
    const m = new Map()
    m.set('name', 'zhw')
    // Map就是一个二维数组 
    const result2 = Object.fromEntries(m)
    console.log(result2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    十四、class类

    这里的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法

    1、实例化一个基本对象

    • 原生js
    function Person(name, age) {
       // new Person() 就会执行这里的代码体
        this.name = name || 'zhw';
        this.age = age;
        // console.log(this);
    }
    Person.prototype.say = function() {
        console.log('i say');
    }
    // 构造函数的静态属性
    Person.p = 'Peron对象上的属性p'  // Peron对象上的属性:会挂载到实例化对象的原型上
    Person.prototype.test = 'Person原型上的属性test' // Person原型上的属性, 会呗实例化对象直接访问到
    let zhw = new Person('zhw', 22)
    // zhw.__proto__.constructor === Person 
    // console.log(zhw.__proto__.constructor === Person);  // true
    console.log(zhw.test);
    console.log(zhw.__proto__ === Person.prototype); // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • class类
    class Person {
       constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        // 类似原生的Person.p
        // 静态属性属于类/或者构造函数, 不属于实例对象
        static p = 'Peron对象上的静态属性p'
        // 类的非静态属性
        test = 'Person原型上的属性test'  // 和构造方法里面的属性同级
        // Person.prototype.say的简化
        // 这块必须是ES6的简介方法,不能出现function关键字的完整写法
        say() {
            console.log('i say'); 
        }
        
    }
    
    let zhw = new Person('zhw', 19)
    // zhw.say()
    // console.log(zhw, 'zhw');
    // 访问类的静态属性
    // console.log(zhw.__proto__.constructor === Person); // true
    // console.log(Person.p);
    
    console.log(zhw.test);
    
    • 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

    2、关于继承

    ES5原生 构造函数实现继承

     // 父构造方法
     // 手机
     function Phone(color, price) {
         this.color = color;
         this.price = price;
     }
     Phone.prototype.call = function() {
         console.log('打电话');
     }
    
     // 子构造方法
     // 智能手机
     function SmartPhone(color, price, size) {
         // this指向SmartPhone
         Phone.call(this, color, price);  // 类似super()
         this.size = size
     }
    
     // 设置子构造函数的原型
    
     // SmartPhone的原型指向了父构造函数  无参构造实例对象
     SmartPhone.prototype = new Phone();
     // 还原SmartPhone的构造函数指向
     SmartPhone.prototype.constructor = SmartPhone;
     
     // 声明子构造函数的方法
     SmartPhone.prototype.playGame = function() {
         console.log('玩游戏');
     }
    
     const HuaWei = new SmartPhone('黑色', 3999, '15px')
     console.log(HuaWei, 'xx');
    
    • 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

    ES6 class类实现继承

    // 父类
    // 手机
    class Phone {
        constructor(color, price) {
            this.color = color;
            this.price = price;
        }
        call() {
            console.log('打电话');
        }
    }
    
    // 子类智能手机
    class SmartPhone extends Phone{
        constructor(color, price,size) {
            // 调用父类的构造函数
            super(color, price);
            this.size = size;
        }
        playGame() {
            console.log('打游戏');
        }
    }
    
    let huaWei = new SmartPhone('黑色', 1000, '大得很');
    console.log(huaWei);
    
    • 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

    3、私有属性

    class Person {
    	// 公有属性
    	name;
    	// 私有属性
    	#sex;
    	constructor(name, sex) {
    		this.name = name;
    		this.#sex = sex;
    	}
    	// 只有在类里面才可以访问私有属性
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    十五、数值的扩展

    • Number.SPSILON: 表示最小精度
    • Number.isFinite : 是否为有限数
    • Number.isNaN: 是否为NaN
    • Number.parseInt : 字符串转整数
    • Number.isInteger: 是否为整数
    • Math.trunc: 将数字的小数部分去掉
    • Math.sign 是否为正数、负数、还是零

    十六、对象的扩展

    • Object.is() : Object.is(NaN,NaN) = true
    • Object.assign() 合并对象
    • Object.entries({}) 对象转二维数组
    • Object.fromEntries([[]]) 二维数组/Map 转 对象

    1、ES8对象方法的扩展

    • Object.values() 返回可以枚举属性的属性值数组
    • Object.entries() 返回可遍历属性的 [key, valuie] 的数组, 【用于转Map对象】
    • Object.getOwnPropertyDescriptors(): 返回指定对象所有属性的描述对象【描述对象指:是否可枚举;是否可更改等】
    const zhw = {
        name: 'zhw',
        age: 18,
        hobbies: ['篮球', 'rap'],
        other: {
            desc: '待定'
        },
    }
    // 获取对象所有的key
    // console.log(Object.keys(zhw)); //  ['name', 'age', 'hobbies', 'other']
    // 获取对象所有的值
    // console.log(Object.values(zhw)); // ['zhw', 18, ['篮球', 'rap'], {desc: '待定'}]
    // 将对象的键值用二维数组包裹起来
    // [
    //     ['name', 'zhw']
    // ]
    
    // 将对象转Map数据结构
    // let m = new Map(Object.entries(zhw))
    // console.log(m.get('name'));
    
    // Object.getOwnPropertyDescriptors(): 获取对象属性的描述对象
    
    // 自定义创建对象
    // zhw将挂载在other_zhw的原型上
    const other_zhw = Object.create(zhw, {
        // 属性名: 描述对象
        errorDesc: {
            value: "另一个我。 错了",
            writable: true,
            configurable: true,
            enumerable: true
        }
    })
    // 不会获取原型上zhw对象的属性描述对象
    // 仅仅打印errorDesc属性的描述对象
    console.log(Object.getOwnPropertyDescriptors(other_zhw))
    
    • 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

    数组的扩展

    1、数组的扁平化

    • arr.flat()
    // 将n维数组  转化为 n - 1维数组
    // const arr = [1, 2, 3, [4, 5]]
     // console.log(arr.flat());  // [1, 2, 3, 4, 5]
    
     // const arr = [1, 2, 3, [4, 5, [6, 7]]]
     // console.log(arr.flat()); // [1, 2, 3, 4, 5, [6, 7]]
    
     const arr = [1, 2, 3, [4, 5, [6, 7]]]
     // 参数: 扁平化的深度  默认是1
     console.log(arr.flat(2)); //  [1, 2, 3, 4, 5, 6, 7]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • arr.flatMap()
    // 需求:一维数组的每个元素 * 10
    const arr = [1, 2, 3, 4]
     // 结果是二维是数组
     // const res = arr.map(item => [item * 10]) // [[10], [20], [30], [40]]
    
     // 此时需要使用flatMap
     const res = arr.flatMap(item => [item * 10]) // [10, 20, 30, 40]
     console.log(res);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    十七、ES6模块化

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

    1、模块化的好处

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

    2、模块化规范的产品

    • CommonJS: NodeJS、Browserify
    • AMD: requireJS
    • CMD: seaJS
    • Import:ES6

    3、ES6模块化的语法

    导出语句

    • 第一种
    export const a = 1;
    export const b = {};
    export const c = () => {}
    
    • 1
    • 2
    • 3
    • 第二种
    const a = 1;
    const b = {};
    const c = () => {}
    export {
    	a,
    	b,
    	c
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 第三种:默认导出
    export default {
    	const a = 1;
    	const b = {};
    	const c = () => {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    导入语句

    • 三种导出方式,通用的导入语句
    // m1 文件别名; as: 取别名关键字
    import * as m1 from './src/js/m1.js
    
    • 1
    • 2
    • 第二种:解构赋值导入
    import {a, b, c} from './src/js/m1.js'
    // 当 当前文件import解构的变量重名时, 可以给重名的变量取别名
    import {a as m2_a }  from './src/js/m2.js'
    // 解构赋值的方法 导入默认导出的文件  也是默认导出文件的  
    import {default as m3 } from './src/js/m3.js'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 第三种:默认导出的简便导入
    // m3: 自定义的
    import m3 from './src/js/m3.js'
    
    • 1
    • 2

    十八、ES7的新特性

    1、数组的includes()

    判断数组中, 是否包含某个元素。替代原生的 indexOf

    2、** 指数运算符

    ** 指数运算符 替代 原生的 Math.pow(2, 10)

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

    十九、bigint大整形

    又一个新的基本类型

    let n = 521n;
    console.log(n, typeof n); // 521n 'bigint'
    
    • 1
    • 2

    1、BigInt函数

    let n = 521;
    console.log(BigInt(n)); // 521n 
    // 参数只能是整数
    console.log(BigInt(1.2)); // error
    
    • 1
    • 2
    • 3
    • 4

    2、应用

    • 大数值运算
    let max = Number.MAX_SAFE_INTEGER;
    //  console.log(max); // 9007199254740991
    //  console.log(max + 1); // 9007199254740992
    //  // 再 + 1 大数值未变
    //  console.log(max + 2); // 9007199254740992
    
    // 希望大数值变化
    console.log(BigInt(max)); // 9007199254740991n
    console.log(BigInt(max) + BigInt(1)); // 9007199254740992n
    // bigint 只能和bigint类型运算  
    // 所以这里的2 也需要转换为bigint再运算
    console.log(BigInt(max) + BigInt(2)); // 9007199254740993n
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    C++常见知识点2
    怎么查看线程的状态及interrupt优雅的关闭线程和interrupt()、interrupted()、isInterrupted()的作用以及区别在哪?
    方差迭代公式推导
    《语音优先》智能语音技术驱动的交互界面设计与语音机器人设计(译者序)...
    英语六级-day9
    Vuex详解(五种状态)
    linux上搭建svn多仓库环境
    锐捷Ruijie交换机补丁升级及补丁卸载
    New Crack:::CAD .NET 14.1.X
    利用 Docker 编译 OpenWrt
  • 原文地址:https://blog.csdn.net/weixin_44224921/article/details/127757333