12.(ECMAScript)es6完全解读(11)

1. 重点提炼

  • 模块化Module
  • 模块化规范
  • es6模块化介绍与总结

2. 模块化Module的发展

技术的诞生是为了解决某个问题,模块化也是。 随着前端的发展,web技术日趋成熟,js功能越来越多,代码量也越来越大。之前一个项目通常各个页面公用一个js,但是js逐渐拆分,项目中引入的js越来越多。在js模块化诞生之前,开发者面临很多问题:

  • 全局变量污染:各个文件的变量都是挂载到window对象上,污染全局变量。
  • 变量重名:不同文件中的变量如果重名,后面的会覆盖前面的,造成程序运行错误。
  • 文件依赖顺序:多个文件之间存在依赖关系,需要保证一定加载顺序问题严重。

模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程, 有多种属性,分别反映其内部特性。百度百科中,模块化的定义是: 模块化是一种处理复杂系统分解为更好的可管理模块的方式。 简单的说,把一个复杂的东西分解成多个甚至多层次的组成部分,以一种良好的机制管理起来,就可以认为是模块化。而对于软件开发来说,函数(过程)就是最常见也是最基本的模块之一。

我觉得用乐高积木来比喻模块化再好不过了。每个积木都是固定的颜色形状,想要组合积木必须使用积木凸起和凹陷的部分进行连接,最后多个积木累积成你想要的形状。

模块化其实是一种规范,一种约束,这种约束会大大提升开发效率。将每个js文件看作是一个模块,每个模块通过固定的方式引入,并且通过固定的方式向外暴露指定的内容。 按照js模块化的设想,一个个模块按照其依赖关系组合,最终插入到主程序中。

模块化的发展 =>

无模块化–>CommonJS规范–>AMD规范–>CMD规范–>ES6模块化

  1. CommonJS规范 Node中模块化规范

    Commonjs的诞生给js模块化发展有了重要的启发,Commonjs非常受欢迎, 但是局限性很明显:Commonjs基于Node原生api在服务端可以实现模块同步加载, 但是仅仅局限于服务端,客户端如果同步加载依赖的话时间消耗非常大,所以需要一个 在客户端上基于Commonjs但是对于加载模块做改进的方案,于是AMD规范诞生了。

  2. AMD规范

    异步模块定义, 允许指定回调函数,AMDRequireJS在推广过程中对模块定义的规范化产出。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。

  3. CMD规范

    同样是受到Commonjs的启发,国内(阿里)诞生了一个CMD(Common Module Definition)规范。该规范借鉴了Commonjs的规范与AMD规范,在两者基础上做了改进。

    CMDSeaJS在推广过程中对模块定义的规范化产出。

    AMD推崇依赖前置、提前执行 CMD推崇依赖就近、延迟执行。

  4. ES6模块化

    到了2015年,ES6规范中,终于将模块化纳入JavaScript标准,从此js模块化被官方扶正,也是未来js的标准。 在ES6中,我们可以使用 import关键字引入模块,通过 exprot关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的, 但是由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的 require


3. 模块化规范

  • CommonJS:Node.js(服务端)
  • AMD:require.js(框架 —— 异步模块定义)
  • CMD:sea.js(框架——阿里推出的)
  • ES6(js中)


4. export

模块功能主要由两个命令构成:exportimportexport命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

即·通过export关键字来导出模块,通过import关键字导入,导入导出对应的变量名称是完全一样的。

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

  1. 导出变量或者常量

      export const name = 'hello'
      export let addr = 'BeiJing City'
      export var list = [1, 2, 3]
    

      const name = 'hello'
      let addr = 'BeiJing City'
      var list = [1, 2, 3]
      export {
          name,
          addr,
          list
      }
    
  2. 导出函数

      export function say(content) {
          console.log(content)
      }
      export function run() {
          console.log('run')
      }
    

      const say = (content) => {
          console.log(content)
      }
      let run = () => {
          console.log('run')
      }
      export {
          say,
          run
      }
    
  3. 导出 Object

      export ({
          code: 0,
          message: 'success'
      })
    

      let data = {
          code: 0,
          message: 'success'
      }
      export {
          data
      }
    
  4. 导出 Class

     class Test {
          constructor() {
              this.id = 2
          }
      }
      export {
          Test
      }
    

      export class Test {
          constructor() {
              this.id = 2
          }
      }
    

5. as

如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。

  const name = 'hello'
  let addr = 'BeiJing City'
  var list = [1, 2, 3]
  export {
      name as cname,
      addr as caddr,
      list
  }

6. export default

使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

  const name = 'hello'
  let addr = 'BeiJing City'
  var list = [1, 2, 3]
  export {
      name as cname,
      addr as caddr
  }
  export default list

7. import

使用export命令定义了模块的对外接口以后,其他 JS文件就可以通过import命令加载这个模块。

  1. 直接导入

    假设导出模块 A 是这样的:

      const name = 'hello'
      let addr = 'BeiJing City'
      var list = [1, 2, 3]
      export {
          name as cname,
          addr as caddr
      }
      export default list
    

    则导入:

      import list, {
          cname,
          caddr
      } from A
    
  2. 修改导入名称

      import list, {
          cname as name,
          caddr
      } from A
    
  3. 批量导入

      import list, * as mod from A
      console.log(list)
      console.log(mod.cname)
      console.log(mod.caddr)
    

8. code演示

es-demo\src\module.js

export const a = 5

es-demo\src\1-27.js

import {a} from './module'
console.log(a)

5

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.26
Branch: branch02

commit description:a3.26(模块化Module——导入与导出)

tag:a3.26


import {aa} from './module'
console.log(aa)

undefined

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.27
Branch: branch02

commit description:a3.27(模块化Module——导入一个与导出不匹配的元素)

tag:a3.27


es-demo\src\module.js

export const a = 5
export const b = 'QACC'

es-demo\src\1-27.js

import {a,b} from './module'
console.log(a,b)

5 “QACC”

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.28
Branch: branch02

commit description:a3.28(模块化Module——导入导出多个变量)

tag:a3.28


导入导出函数和对象,注意导出对象的格式有所不同。

export const a = 5
export const b = 'QACC'
export const sum = (x, y) => x + y
const obj = {
    name: 'es'
}
export {obj}
import {
    a,
    b,
    sum,
    obj
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)

image-20201127125615018

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.29
Branch: branch02

commit description:a3.29(模块化Module——导入导出函数和对象)

tag:a3.29


以上导出实际定义了很多个模块,用了很多个export导出会很麻烦,实际可以统一地导出。

es-demo\src\module.js

const a = 5
const b = 'QACC'
const sum = (x, y) => x + y
const obj = {
    name: 'es'
}

export {
    a,
    b,
    sum,
    obj
}
import {
    a,
    b,
    sum,
    obj
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)

image-20201127125615018

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.30
Branch: branch02

commit description:a3.30(模块化Module——统一导出)

tag:a3.30


定义一个类,导出并导入。

实际上在es上的各种结构都可以导入导出。

es-demo\src\module.js

const a = 5
const b = 'QACC'
const sum = (x, y) => x + y
const obj = {
    name: 'es'
}

class People {
    constructor(name) {
        this.name = name
    }
    showName() {
        console.log(this.name)
    }
}

export {
    a,
    b,
    sum,
    obj,
    People
}

es-demo\src\1-27.js

import {
    a,
    b,
    sum,
    obj,
    People
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()

image-20201127130454873

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.31
Branch: branch02

commit description:a3.31(模块化Module——类导出并导入)

tag:a3.31


但是有的时候可能有这样的问题,导出的时候,名字都是起好的,导入的时候想重命名,即起别名。

注意:如果起了别名,原来的名字就不能被使用了。

import {
    a as aa,
    b,
    sum,
    obj,
    People
} from './module'
console.log(a,aa,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()

image-20201127130759129

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.32
Branch: branch02

commit description:a3.32(模块化Module——如果起了别名,原来的名字就不能被使用了)

tag:a3.32


import {
    a as aa,
    b,
    sum,
    obj,
    People
} from './module'
console.log(aa,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()

image-20201127130454873

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.33
Branch: branch02

commit description:a3.33(模块化Module——如果起了别名,就直接使用别名即可)

tag:a3.33


综上实际上甭管导入什么,都必须得知道导出的元素名是什么!

有时导入别人定义好的模块,但模块中的代码逻辑非常复杂,但是作为使用者肯定想快速上手,不去阅读他的源码或者文档。

=> 利用export default导出,导入的时候名字随意取即可。

es-demo\src\module.js

const a = 5
export default a

es-demo\src\1-27.js

import aa from './module'
console.log(aa)

5

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.34
Branch: branch02

commit description:a3.34(模块化Module——export default)

tag:a3.34


const a = 5
export default a
const b = 'QACC'
export default b

报错,因为在每一个模块只能有一个export default。实际很好理解,默认值只能有一个,多了的话,没法区分了。

image-20201127132701908

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.35
Branch: branch02

commit description:a3.35(模块化Module——每一个模块只能有一个export default)

tag:a3.35


export default必须先定义后导出,这点与export不一样。

export default const a = 5 // 错误

image-20201127133041991

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.36
Branch: branch02

commit description:a3.36(模块化Module——export default必须先定义后导出)

tag:a3.36


es-demo\src\module.js

function sum(x, y) {
    return x + y
}
export default sum

es-demo\src\1-27.js

import add from './module'
console.log(add(4, 5))

9

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.37
Branch: branch02

commit description:a3.37(模块化Module——export default导出函数)

tag:a3.37


同一个模块可以有exportexport default同时存在 =>

export对应导入需要加{},而export default直接导入即可

es-demo\src\module.js

function sum(x, y) {
    return x + y
}
export default sum

export const str = 'abc'

es-demo\src\1-27.js

import add, {str} from './module'
console.log(add(4, 5), str)

9 “abc”

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.38
Branch: branch02

commit description:a3.38(模块化Module——export和export default同时存在)

tag:a3.38


一般情况下,会把多种数据放在一个对象中,通过export default导出 =>

es-demo\src\module.js

const a = 5
const b = 'abc'
const sum = (x, y) => x + y
const obj = {
    name: 'es'
}
class People {
    constructor(name) {
        this.name = name
    }
    showName() {
        console.log(this.name)
    }
}
export default {
    a,
    b,
    sum,
    obj,
    People
}

es-demo\src\1-27.js

import mod from './module'
console.log(mod.a)
console.log(mod.b)
console.log(mod.obj)
console.log(mod.sum(7, 8))

image-20201127134046823

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.39
Branch: branch02

commit description:a3.39(模块化Module——export default统一导出)

tag:a3.39


假如一个文件需要导入了很多属性,利用通配符*即可完成全部导入。

import * as mod from './module'
console.log(mod)
console.log(mod.default.a)
console.log(mod.default.b)
console.log(mod.default.sum(8, 9))

image-20201127134307929

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.40
Branch: branch02

commit description:a3.40(模块化Module——export default利用通配符统一导出)

tag:a3.40


9. es6 导入导出关键字总结

  • export
  • import
  • as
  • export default
  • from



(后续待补充)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值