• JavaScript 笔记1 ES6 新特性 | 解构赋值、模板字符串、Symbol数据类型、Promise、模块化



    参考资料:

    1. ECMAScript

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

    ECMAScript 简称 ES,是脚本语言的规范,平时编写的 JavaScript,是 ECMAScript规范的一种实现,ES 新特性指的是 JavaScript 新特性

    ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言,发展历史如下:
    (ECMA-262 是 Ecma国际制定了许多标准中的一个)

    ECMA版本发布日期新特性
    11997 年制定了语言的基本语法
    21998 年较小改动
    31999 年引入正则、异常处理,格式化输出等,IE浏览器开始支持
    42007年未发布
    52009年引入严格模式,JSON、扩展对象、数组、原型、字符串、日期方法
    62015年模块化,面向对象语法、Promise、箭头函数、let、const、数组解构赋值等等
    72016年幂运算符、数组扩展、Async/await 关键字
    82017年Async/await 、字符串扩展
    92018年对象解构赋值,正则扩展
    102019年扩展对象、数组方法

    注:从 ES6 开始,每年发布一个版本,版本号比年份最后一位大1

    TC39 (Technical Committee 39)是推进 ECMAScript 发展的委员会,其会员都是各种公司(主要是浏览器厂商,有苹果、谷歌、微软等)。
    TC39 会定期召开会议,会议由会员公司的代表与特邀专家出席

    2. ES6

    为什么要学习 ES6

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

    ES6与不同浏览器版本的兼容性查询
    http://kangax.github.io/compat-table/es6/
    在这里插入图片描述

    3. let 、const

    let 是 ES6 新推出的数据类型,let 用于声明变量,若不赋值,则默认为 undefined 类型

    1. 变量不能重复声明
    2. 块级作用域,相当于局部变量
    {
       let name = 'uni' 
    }
    console.log(name)	// 报错, 无法访问
    
    • 1
    • 2
    • 3
    • 4

    这里包括但不限于 if、else、while、for 、funtion 所包含的 { }

    1. 不存在变量提升,不允许在变量声明前就去使用
    2. 不影响作用域链,所在作用域的内部函数可以访问到变量
    let name = 'uni';
    function fn(){
       console.log(name); 
    }
    fn();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    const 用于声明常量

    1. 在定义时必须赋值初始值
    2. 一般常量使用大写
    3. 常量的值不能修改
    4. 块级作用域
    {
       const NAME = 'uni' 
    }
    console.log(NAME)	// 报错
    
    • 1
    • 2
    • 3
    • 4
    1. 支持对数组类型修改
    const users = []
    users.puth('uni')
    
    • 1
    • 2

    4. 解构赋值

    解构赋值:ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值
    解构赋值一般分为数组和对象这两种
    【例】对数组进行解构赋值

    const words = ['a', 'b', 'c']
    let [a, b, c] = words
    // a = 'a'
    // b = 'b'
    // c = 'c'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    【例】对对象进行解构赋值

    const user={
       id: 1,
       name: 'uni',
       say: function(){
          console.log(`name: ${name}, id: ${id}`)
       }
    }
    let {id, name, say} = user;
    say()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5. 模板字符串

    使用 反引号,支持使用 ${} 取值,例:

    let name = 'uni'
    console.log(`name: ${name}`)
    
    • 1
    • 2

    6. 对象的简化写法

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

    let name = 'uni'
    let say = function(){
       console.log(`name: ${uni}`)
    }
    const uni = {name, say}
    // 相当于: const uni = {name: name, say: say}
    console.log(uni)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7. 箭头函数

    ES6 允许使用 =>箭头 定义函数
    【例】定义求和函数

    let fn = (a, b) => { return a + b } 
    
    • 1

    箭头函数的特性:

    1. this 是静态的,this 始终指向函数声明时所在作用域下的 this 的值

    【例】直接调用两种定义方式的函数

    function getName(){
        console.log(this.name)
    }
    function getName2(){
        console.log(this.name); 
    }
    window.name = 'uni',
    const school = {
       name: 'UNI' 
    }
    console.log(getName())
    console.log(getName2())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果
    uni
    uni

    例,使用 call 来改变函数的this

    getName.call(school)
    getName2.call(school)
    
    • 1
    • 2

    运行结果
    UNI
    UNI

    1. 不能作为构造实例化对象

    【例】箭头函数的错误使用

    let Person = (name, age) => {
      this.name = name
      this.age = age
    }
    let uni = new Person('uni', 22)
    console.log(uni)		// 报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 不能使用 arguments 变量
    let fn = () => {
      console.log(arguments);
    }
    
    • 1
    • 2
    • 3
    1. 箭头函数可简写
    • 当形参只有一个时可省略小括号

    简写前

    let abs = (a) => {
      if(a < 0)
        return -a;
      else 
        return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    简写后

    let abs = a => {
      if(a < 0)
        return -a;
      else 
        return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 省略花括号,当代码只有一条语句时,此时的 return 必须省略,语句执行结果即为函数返回值
    // 简写前
    let pow = (n) => {
       return n * n 
    }
    // 简写后
    let pow2 = n => n * n
    console.log(pow(1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用场景:

    1. 适合与 this 无关的回调,例如定时器,数组的方法等回调
    2. 不适合与 this 有关的回调,事件回调

    8. 函数参数初始值

    ES6 允许给函数参数赋值默认值,经常与解构赋值结合使用
    【例】

    function connect({
      host="127.0.0.1",
      username,
      password,
      port
    })
    connect({username: 'root', password: 'root', port: 3306})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    9. REST 参数

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

    // ES5 获取实参的方式
    function data(){
      console.log(arguments);
    }
    data(1,2,3)
    
    // ES6 使用 rest 参数
    function data(...args){
       console.log(args) 
    }
    data(1,2,3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    rest 参数必须要放到参数最后

    10. 拓展运算符

    ES6 的扩展运算符能将数组转换为逗号分隔的参数序列

    const words = ['a', 'b', 'c']
    
    function data(...args){
      console.log(args)  
    }
    data(...words)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    11. Symbol 数据类型

    11.1 Symbol 类型的特点

    ES6 引入了一种新的基本数据类型 (第八种)Symbol,表示独一无二的值,类似于字符串。
    Symbol 数据的类型的特点有:

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

    11.2 Symbol 类型的基本使用

    // 1. 创建 Symbol
    let s1 = Symbol();
    console.log(s1, typeof s1) // Symbol() "symbol"
    let s2 = Symbol('uni')
    let s3 = Symbol('uni')
    console.log(s2 == s3) 	// false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
    【例】

    let s4 = Symbol.for('hello')
    let s5 = Symbol.for('hello')
    console.log(s4 === s5) // true
    
    • 1
    • 2
    • 3

    Symbol 可用于表示对象唯一的属性,例如:

    let methods = {
       say1: Symbol(),
       say2: Symbol()
    }
    let game = {}
    game[methods.say1] = function(){ console.log('say1'); }
    game[methods.say2] = function(){ console.log('say2'); }
    
    game[methods.say1]()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    除了上述这种方法,先定义包含 Symbol() 属性的对象外,还有更简化的方法,直接在定义方法时创建 Symbol 对象,例如:

    
    let game = {
      [Symbol('say1')]: function(){ console.log('say1'); },
      [Symbol('say2')]: function(){ console.log('say2'); }
    }
    // 这里的 Symbol('say1') 无法调用,通常是使用 Symbol 的内置属性来代替
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    11.3 Symbol 内置属性

    除了定义自己使用的 Symbol 值意外, ES6 还提供了 11个内置的 Symbol 值,指向语言内部使用的方法,等用到的时候可以查看文档
    参考资料:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol
    在 Symbol 的这些内置属性中,比较关键的就是 iterator 迭代器
    Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for…of 循环使用。

    12. 迭代器

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

    1. ES6 创造了一种新的遍历命令 for … of 循环, iterator 接口主要供 for… of 消费
    2. 原生具备了 iterator 接口的数据(可用 for of 遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypeArray
    • NodeList
    1. 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的 next 方法,指针一直往后移动,直到指向最后一个成员
    • 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
    • 每当调用 next() 方法,就会返回一个包含 value 和 done 属性的对象

    【例】

    const words = ['a', 'b', 'c']
    
    for(let word of words){
       console.log(word) 
    }
    // a
    // b
    // c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过输出一个空的数组,我们可以观察到其原型对象支持迭代遍历的实现对象

    console.log(new Array())
    
    • 1

    运行的部分结果:
    在这里插入图片描述

    可以看到在 Array 类型数据的 prototype 原型对象中,包含了 Symbol 类型的属性名,其值为一个 values() 函数
    【例】遍历数组的迭代器

    a = [1,2,3]
    
    let iterator = a[Symbol.iterator]()
    // 调用对象的 next
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:
    在这里插入图片描述

    12.1 自定义迭代器

    自定义迭代器分为两步,1)声明 Symbol.iterator 属性,值为 一个函数,2)该函数需返回 next()方法
    【例】实现只遍历长度 >= 2 的字符串数据,其他则为 undefined

    const users = {
      data: ['aa', 'bb', 'cc', 'A', '1', 'DD'],
      [Symbol.iterator](){
         // 索引变量
         let index = 0
         let _this = this
         return {
            next: function(){
                if(index >= _this.data.length) 	// 若索引不合理, 则迭代结束
                  return { value: undefined, done: true }
              
                if(_this.data[index].length >= 2)
                   return { value: _this.data[index++], done: false }
                else{
                   index++
                   return { value: undefined, done: false }
                }
                
            }
         }
      }
    }
    for (let u of users){ 
      console.log(u)
    }
    
    • 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

    13. 生成器

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

    function * gen(){
      console.log(1);
      yield '1';	// 类似于断点
      
      console.log(2);
      yield '2';
      
      console.log(3);
      yield '3';
      
    }
    let iterator = gen();
    iterator.next();
    iterator.next();
    iterator.next();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    13.1 生成器函数的参数传递

    调用 生成器函数的 next()方法时,方法里传递的参数会作为函数执行 yield 方法后的返回值

    function * gen(arg){
      console.log(arg);
      let aaa = yield 1
      console.log(aaa)
      let bbb = yield 2
      console.log(bbb)
      let ccc = yield 3
      console.log(ccc)
    }
    let iterator = gen('hi')
    console.log(iterator.next('aaa'))
    console.log(iterator.next('bbb'))
    console.log(iterator.next('ccc'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:
    在这里插入图片描述

    13.2 生成器实例

    了解回调地狱 callback hell

    参考资料:http://callbackhell.com/
    回调:使用 JavaScript 函数的约定的名称,通常在执行 I/O时实行,例如下载文件,读取文件,数据库连接等。

    回调通常发生在 异步 async 操作中,异步是指多个操作同时进行,常见的有 setTimeout 延时函数 和 AJAX 发送请求等

    回调地狱:回调函数中又嵌套了一个或多个回调,例:在3秒内分别输出3, 2,1

    setTimeout(() => {
      console.log(3)
      setTimeout(() => {
         console.log(2) 
         setTimeout(() => {
            console.log(1) 
         }, 1000)
      }, 1000)
    }, 1000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用生成器函数可以解决回调地狱的问题:

    function one(){
      setTimeout(() => {
        console.log(1)
      }, 3000)
    }
    
    function two(){
       setTimeout(() => {
         console.log(2) 
       }, 2000)
    }
    
    function three(){
        setTimeout(() => {
          console.log(3) 
        }, 1000)
    }
    
    function * gen(){
      yield three();
      yield two();
      yield one();
    }
    let iterator = gen()
    iterator.next()
    iterator.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

    返回值具有关联的回调地狱如何解决呢?比如要先后获取用户数据、订单数据和商品数据

    function getUsers(){
      setTimeout(() => {
        let data = '用户数据'
        iterator.next(data)
      }, 3000)
    }
    
    function getOrders(){
       setTimeout(() => {
         let data = '订单数据'
         iterator.next(data)
       }, 2000)
    }
    
    function getGoods(){
        setTimeout(() => {
          let data = '商品数据'
          iterator.next(data)
        }, 1000)
    }
    
    function * gen(){
      let users = yield getUsers();
      console.log(users)
      let orders = yield getOrders();
      console.log(orders)
      let goods = yield getGoods();
      console.log(goods)
    }
    let iterator = gen()
    iterator.next()
    
    • 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

    14. Promise

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

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

    promise 译为 承诺,里面主要有 resolve 决定 和 reject 拒绝 这两个行为

    // 定义 Promise
    const p = new Promise(function(resolve, reject){
        if(...)
          reject(a)
        else
          resolve(b)
    }
    
    // 使用 Promise
    p.then(
       (a) => {},
       (b) => {}
    ).catch(error => {}) 	// 捕获异常
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    14.1 使用 Promise 封装 AJAX 请求

    需要node环境,使用node命令执行下方的 JS代码
    原生的 AJAX 异步请求实现

    
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    // 该 API 接口可以随机返回一条诗句
    const url = 'https://api.apiopen.top/api/sentences'
    // 1. 创建对象
    const xhr = new XMLHttpRequest();
    // 2. 初始化
    xhr.open("GET", url)
    // 3. 发送
    xhr.send()
    // 4. 绑定事件,处理响应结果
    xhr.onreadystatechange = function(){
       if(xhr.readyState === 4){
          // 判断状态响应码
          if(xhr.status >= 200 && xhr.status < 300){  // 成功
             console.log(xhr.responseText) 
          } else{																			// 失败
             console.error(xhr.status)
          }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行结果
    {“code”:200,“message”:“成功!”,“result”:{“name”:“河海不择细流,故能就其深
    ;”,“from”:“李斯《谏逐客书》”}}

    使用 Promise 封装原生的 AJAX 请求

    
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    
    // 定义 Promise
    const p = new Promise((resolve, reject) => {
        const url = 'https://api.apiopen.top/api/sentences'
        // 1. 创建对象
        const xhr = new XMLHttpRequest();
        // 2. 初始化
        xhr.open("GET", url)
        // 3. 发送
        xhr.send()
        // 4. 绑定事件,处理响应结果
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                // 判断状态响应码
                if(xhr.status >= 200 && xhr.status < 300){  // 成功
                    resolve(xhr.responseText) 
                } else{																			// 失败
                    reject(xhr.status)
                }
            }
        }
    })
    // 调用 Promise
    p.then(
        (result) => {
            console.log('请求成功', result)
        },
        (reason) => {
            console.log('请求失败', reason)
        }
    ).catch((error) => {
        console.error('程序出错', error)
    })
    
    • 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

    15. Set

    ES6 提供了新的数据结构 Set(集合),类似于数组,其内部的值都是唯一的。
    Set 集合实现了 iterator 接口,所以可使用 for…of 进行遍历
    集合的属性和方法:

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

    【例1】使用 Set 去重

    let arr = [1,1,2,2,2,3,3]
    let result = [...new Set(arr )];
    console.log(result);
    
    • 1
    • 2
    • 3

    【例2】 使用 Set 求两个数组的交集

    let arr1 = [1,1,2,2,2,3,3]
    let arr2 = [3,3,2]
    let result = [...new Set(arr1)].filter(
        item => {
            let a2 = new Set(arr2)
            if(a2.has(item))
                return true
            else 
                return false
        }
    )
    console.log(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    简化写法

    let result = [...new Set(arr1)].filter(item => new Set(arr2).has(item)); 
    
    • 1

    【例3】 使用 Set 求两个数组的并集

    let arr1 = [1,1,2,2,2,3,3]
    let arr2 = [3,3,2]
    let result = [...new Set([...arr1, ...arr2])]
    console.log(result)
    
    • 1
    • 2
    • 3
    • 4

    【例4】使用 Set 求两个数组的差集

    let arr1 = [1,1,2,2,2,3,3]
    let arr2 = [3,3,2]
    
    let diff = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item)))
    console.log(diff)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16. Map

    ES6 提供了 Map 数据结构,类似于 Object,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了 iterator 接口,所以可以使用 for…of 进行遍历,Map 的常用方法有:

    1. size,返回 Map 的元素个数
    2. set,增加新元素,返回当前的 Map
    3. get,返回指定键的值
    4. has,检测 Map 中是否包含某个元素,返回结果为 boolean 类型
    5. clear,清空集合,返回 undefined
    map = new Map()
    map.set('name', 'uni')
    map.set('age', 22)
    
    for(let node of map){
        console.log('key=',node[0], ',value=',node[1])
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    17. Class

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

    1. class 声明类
    2. constructor 定义构造函数初始化
    3. extends 继承父类
    4. super 调用父类构造方法
    5. static 定义静态方法和属性
    6. 父类方法可以重写

    17.1 Class 基本使用

    【例】面向对象编程(ES5的写法)

    function User(name, age){
        this.name = name;
        this.age = age
    }
    // 给类添加方法
    User.prototype.sayHello = function(){
        console.log(`My name is ${this.name}, age is ${this.age}`)
    }
    // 实例化对象
    let Uni = new User('Uni', 22)
    // 调用对象的方法
    Uni.sayHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果
    My name is Uni, age is 22

    ES6的写法

    class User{
       // 构造方法
        constructor(name, age){
           this.name = name;
           this.age = age; 
        }
        // ES6 Class类里的方法必须使用方法名() ,而不能使用 ES5的 方法名:function()
        sayHello(){
            console.log(`My name is ${this.name}, age is ${this.age}`)
        }
    }
    let Uni = new User('Uni', 22)
    Uni.sayHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ES6 的 Class 支持静态属性,使用 static 关键字定义

    class User{
        // 静态属性
        static body = 'normal'
        // 构造方法
         constructor(){}
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    17.2 对象继承

    【例】面向对象编程实现手机类 (ES5写法)

    // 定义父类手机
    function Phone(brand, price){
        this.brand = brand
        this.price = price
    }
    // 定义方法
    Phone.prototype.call = function(){
        console.log('打电话')
    }
    // 定义子类
    function SmartPhone(brand, price, color, size){
        // 调用父类的构造方法并修改父类的 this 指向
        Phone.call(this, brand, price)
        this.color = color
        this.size = size
    }
    //设置子级构造函数的原型
    SmartPhone.prototype = new Phone
    SmartPhone.prototype.constructor = SmartPhone
    
    // 声明子类的方法
    SmartPhone.prototype.phone = function(){
        console.log('拍照')
    }
    const HuaWei = new SmartPhone('华为', 3099, '黑色', '5.5英寸')
    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

    运行结果
    SmartPhone { brand: ‘华为’, price: 3099, color: ‘黑色’, size: ‘5.5英寸’ }

    使用 ES6 实现上述案例:

    class Phone{
        constructor(brand, price){
            this.brand = brand
            this.price = price
        }
        call(){
            console.log('打电话')
        }
    }
    class SmartPhone extends Phone{
        constructor(brand, price, color, size){
            super(brand, price) // 相当于 Phone.call(this, brand, price)
            this.color = color
            this.size = size
        }
        photo(){ console.log('拍照') }
    }
    
    const HuaWei = new SmartPhone('华为', 3099, '黑色', '5.5英寸')
    console.log(HuaWei)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    17.3 子类重写父类方法

    class A{
        constructor(){}
        hello(){ console.log('A: hello')}
    }
    class B extends A {
        constructor(){super()}
        hello() { 
            // 重写方法时可调用父类的方法
            super.hello(); 
            console.log('B: hello')}
    }
    b = new B()
    b.hello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    17.4 get 和 set

    【例】

    class Phone{
        // constructor 构造函数可以不写
        get price(){            // 默认返回当前属性值
           console.log('价格属性被读取')
           return this.p
        }
        set price(val){
            console.log('价格属性被修改')
            this.p = val
        }
    }
    let phone = new Phone()
    
    console.log(phone.price) // undefined
    
    phone.price = 100
    
    console.log(phone.price)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行结果
    价格属性被读取
    undefined
    价格属性被修改
    价格属性被读取
    100

    18. ES6 Number 类型拓展

    Number.EPSILON 可以表示最小精度,用于浮点数之间的运算,当两个数的差值小于这个精度时候,则视为相等,默认值为 2.220446049250313e-16

    0b 可表示二进制,0o表示八进制,0x表示十六进制

    console.log(0b1010)
    console.log(0o12)
    console.log(10)
    console.log(0xA)
    
    • 1
    • 2
    • 3
    • 4

    运行结果
    10
    10
    10
    10

    **Number.isFinite **检测一个数值是否为有限数

    console.log(Number.isFinite(100))       // true
    console.log(Number.isFinite(100/0))     // false
    console.log(Number.isFinite(Infinity))  // false
    
    • 1
    • 2
    • 3

    Number.isNaN 判断是否为 NaN类型

    console.log(Number.isNaN(1))                    // false
    console.log(Number.isNaN('2'))                  // false
    console.log(Number.isNaN(new Number('3a')))     // false
    console.log(Number.isNaN(new Number('a')))      // false
    console.log(Number.isNaN(NaN))                  // true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    19. ES6 对象方法的拓展

    1. Object.is 判断两个值是否完全相等
    console.log(Object.is(NaN, NaN)) // true
    console.log(NaN === NaN)         // false
    
    • 1
    • 2
    1. Object.assign 对象的合并
    const config1 = {
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: '123456',
    }
    const config2 = {
        host: '127.0.0.1'
    }
    console.log(Object.assign(config1, config2))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行效果
    { host: ‘127.0.0.1’, port: 3306, username: ‘root’, password: ‘123456’ }

    1. Object.setPrototypeOf ,Object.getPrototypeof 给实例对象的构造函数设置原型对象
    const user = { name: 'uni'}
    const role = { name: '普通用户'}
    Object.setPrototypeOf(user, role)
    console.log('user:', user)
    console.log('getPrototypeOf:', Object.getPrototypeOf(user))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果
    user: { name: ‘uni’ }
    getPrototypeOf: { name: ‘普通用户’ }

    20. ES6 模块化

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

    模块化的优势:

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

    ES6 之前的模块化规范:
    CommonJS => NodeJS、Browserify
    AMD => requireJS
    CMD => seaJS
    ES6 模块化语法:
    模块功能主要由两个命令构成:export 和 import

    • export 用于规定模块的对外接口
    • import 用于输入其他模块提供的功能

    【例】
    uni.js

    export let name = 'uni'
    
    export function sayHello(){
        console.log(`hi, i am ${name}`)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    index.html

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Documenttitle>
      head>
      <body>
        <script type="module">
          import * as uni from './static/uni.js'
          console.log(uni)
        script>    
      body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:
    在这里插入图片描述

    除了上述的 export 方法以外,还可以统一 export

    let name = 'uni'
    
    function sayHello(){
        console.log(`hi, i am ${name}`)
    }
    
    export { name, sayHello }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ES6 支持 默认的 export,这样在 import 的时候,需通过 default 来调用里面的属性或方法

    export default {
        name: 'uni',
        sayHello(){
          console.log(`hi, i am ${name}`)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    20.1 import 时使用解构赋值

    ES6 支持 解构赋值的方式导入其他的模块

    // 导入统一的export
    import {name, sayHello} from './static/uni.js'
    // 导入默认的export
    import {default as uni} from './static/xxx.js'
    
    • 1
    • 2
    • 3
    • 4

    20.2 默认export的导入

    如果要 import 的 js 文件是使用 export default 方式导出的,那么则可以简写import

    import xxx from 'xxx.js'
    
    • 1

    20.3 import 引入的第二种方式

    假设 app.js 是 web 程序的入口脚本文件,通常需要引入一些内容
    uni.js

    export let name = 'uni'
    
    export function sayHello(){
        console.log(`hi, i am ${name}`)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    app.js

    import * as uni from './static/uni.js'
    console.log(uni)
    
    • 1
    • 2

    index.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Documenttitle>
    head>
    <body>
        <script src="./static/app.js" type="module">script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    20.4 ES6 模块化代码转换

    Babel 官网:https://www.babeljs.cn/docs/
    Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
    这里以了解为主,用到的时候再查阅相关资料

  • 相关阅读:
    Glide缓存机制
    【Python】高级变量类型
    125. 验证回文串
    react hook:useMemo
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    Spring框架讲解笔记:spring框架学习的要点总结
    gbase 8a 基础语法概念问题
    FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
    高效调度新篇章:详解DolphinScheduler 3.2.0生产级集群搭建
    MultiPlayerShoot----C++学习记录02人物
  • 原文地址:https://blog.csdn.net/Unirithe/article/details/126369972