JavaScript模块化使用及详解

JavaScript模块化

认识 ES Module

  • JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等, 所以在ES推出自己的模块化系统时,大家也是兴奋异常

  • ES Module和CommonJS的模块化有一些不同之处: 一方面它使用了import和export关键字; 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式

  • ES Module模块采用export和import关键字来实现模块化:

    export负责将模块内的内容导出;

    import负责从其他模块导入内容;

  • 了解:采用ES Module将自动采用严格模式:use strict

下载Live Serve 插件

这里我在浏览器中演示ES6的模块化开发:

image-20220918143611227

如果直接在浏览器中运行代码,会报如下错误;

image-20220918143622734

报错原因:由于JavaScript模块的安全需要,如果通过本地加载html文件(如:file://路径的文件),就会遇到CORS错误。如上图所示。

解决方法:需要通过一个服务器来测试,这里我们使用vscode的一个插件来辅助开发——Live Server

安装好Live Server后,右键Open with Live Server启动本地服务器。控制台出现Live reload enabled.说明启动成功了

image-20220918144339107

image-20220918144647276

exports关键字

我们希望把一个模块中的变量、函数、类导出给其他模块使用时。需要用到export关键字

可以有如下三种方式:

  • 方式一:在语句声明的前面直接加上export关键字
  • 方式二:将所有需要导出的标识符,放到export后面的 {}中
  • 注意:这里的 {}里面不是ES6的对象字面量的增强写法,{}也不是表示一个对象的; 所以: export {name: name},是错误的写法;
  • 方式三:导出时给标识符起一个别名

import关键字

当我们希望从外部模块导入变量、函数、类给本模块使用时。需要用到import关键字

可以有以下三种方式:

方式一:import {标识符列表} from ‘模块’;

注意:这里的{}也不是一个对象,里面只是存放导入的标识符列表内容;

方式二:导入时给标识符起别名

方式三:通过 * 将模块功能放到一个模块功能对象(a module object)上

export-import用法

基本使用

建立文件目录如下:

image-20220918201622718

代码示例:

foo.js使用exports导出

  • 方式一: export 声明语句

    export const name = "ikun"
    export const age = 18
    
    export function foo() {
      console.log("只因你太美")
    }
    
    // export class Person {
    
    // }
    
  • 方式二: export 导出 和 声明分开

    const name = "ikun"
    const age = "18"
     function foo(){
        console.log("只因你太美")
     }
     export {
        name,
        age,
        foo
     }
    
  • 方式三: 第二方式导出时起别名

    const name = "ikun"
    const age = "18"
     function foo(){
        console.log("只因你太美")
     }
     export {
      name as fName,
      age as fAge,
      foo as fFoo
    }
    

main.js使用import 导入

  • 方式一: 普通的导入

    import { name, age, foo } from "./foo.js"
    // import { fName, fAge, fFoo } from './foo.js'
    //export导出的时候设置了别名就使用别名导入
    
    console.log(name)
    console.log(age)
    foo()
    // console.log(fName)
    // console.log(fAge)
    // fFoo()
    
  • 方式二: 导入时起别名

    import { name as fName, age as fAge, foo as fFoo } from "./foo.js"
    console.log(fName)
    console.log(fAge)
    fFoo()
    
  • 方式三: 将导出的所有内容放到一个标识符中

    import * as foo from "./foo.js"
    console.log(foo.name)
    console.log(foo.age)
    foo.foo()
    

index.html执行main.js的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script src="./main.js" type="module"></script>
</html>

输出结果;

image-20220918203612862

export-import结合使用

为什么要这样做呢?在开发和封装一个功能库时,通常我们希望将暴露的所有接口放到一个文件中。这样方便指定统一的接口规范,也方便阅读; 这个时候,我们就可以使用export和import结合使用。如果在vue项目中封装过axios请求的小伙伴,会深有体会。

下面我们看具体的代码示例:

目录结构如下:

image-20220918214830871

format.js

function timeFormat() {
  return "2222-12-12"
}

function priceFormat() {
  return "222.22"
}

export {
  timeFormat,
  priceFormat
}

math.js

function add(num1, num2) {
  return num1 + num2
}
function sub(num1, num2) {
  return num1 - num2
}

export {
  add,
  sub
}

index.js(接口集中到这个文件管理)

方式一:

import { add, sub } from './math.js'
import { timeFormat, priceFormat } from './format.js'

export {
  add,
  sub,
  timeFormat,
  priceFormat
}

方式二:export、import结合使用

export { add, sub } from './math.js'
export { timeFormat, priceFormat } from './format.js'

方式三:使用*全部导出

export * from './math.js'
export * from './format.js'

request.js

export function request() {
//   在这里封装一些库的请求,如axios等
}

main.js

import { add, sub,timeFormat,priceFormat } from "./utils/index.js"
console.log(add(10,20))
console.log(sub(20,10))
console.log(timeFormat())
console.log(priceFormat())

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="./main.js" type="module"></script>
</body>
</html>

default用法

前面我们学习的导出的功能都是有名字的导出(named exports),在导出export时指定了名字; 在导入import时需要知道具体的名字。

还有一种导出叫默认导出(default export)

  • 默认导出export时可以不需要指定名字;

  • 在导入时不需要使用 {},并且可以自己来指定名字;

  • 它也方便我们和现有的CommonJS等规范相互操作

注意:在一个模块中,只能有一个默认导出(default export);

下面我们代码演示一下具体的用法:

foo.js

const name = "ikun"
const foo = "只因你太美"

export {
    name
}
export default foo

main.js

import {name} from "./foo.js"

console.log(name)

// 导入语句: 导入的默认的导出,可以自己来指定名字
import ikun from './foo.js'
console.log(ikun)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script src="./main.js" type="module"></script>
</html>

输出结果:

image-20220918221903827

import函数

当我们通过import加载一个模块,是不可以在其放到逻辑代码中的

为什么会出现这个情况呢?

因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;

由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;

甚至下面的这种写法也是错误的:因为我们必须到运行时能确定path的值

image-20220918222237255

但是某些情况下,我们确确实实希望动态的来加载某一个模块,根据不同的条件,动态来选择加载模块的路径,这个时候我们就需要使用import()函数来动态加载;

下面我们看具体代码示例:

目录结构:

image-20220918225844783

boo.js

const foo = "唱、跳、rap、篮球"
const name = "ikun"
export {
  name,
  foo
}

foo.js

const name = "ikun"
const massage = "只因你太美"
function foo(){
  return this.massage
}
export {
  name,
  massage,
  foo
}

mian.js

let flag = true
// let flag = false

// import函数返回的结果是一个Promise
if (flag) {
    import("./foo.js").then(res => {
        console.log("name:", res.name)
        console.log(res.foo())
    })
}else{
    import("./boo.js").then(res => {
        console.log("name:", res.name)
        console.log(res.foo)
    })
}

index.html

tml lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script src="./main.js" type="module"></script>
</html

输出结果:

image-20220918230056518

image-20220918230207640

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值