javascript中的modules、import和export

2023-05-16

在互联网的洪荒时代,网站主要用 HTML和 CSS 开发的。如果将 JavaScript 加载到页面中,通常是以小片段的形式提供效果和交互,一般会把所有的 JavaScript 代码全都写在一个文件中,并加载到一个 script 标签中。尽管可以把 JavaScript 拆分为多个文件,但是所有的变量和函数仍然会被添加到全局作用域中。

但是后来 JavaScript 在浏览器中发挥着重要的作用,迫切需要使用第三方代码来完成常见任务,并且需要把代码分解为模块化的文件,避免污染全局命名空间。

ECMAScript 2015 规范在 JavaScript 语言中引入了 module,也有了 import 和 export 语句。在本文中,我们一起来学习 JavaScript 模块,以及怎样用 import 和 export 来组织代码。

模块化编程

在 JavaScript 中出现模块的概念之前,当我们想要把自己的代码组织为多个块时,一般会创建多个文件,并且将它们链接为单独的脚本。下面先举例说明,首先创建一个 index.html 文件和两个JavaScript文件“ functions.js 和 script.js

index.html 文件用来显示两个数字的和、差、乘积和商,并链接到 script 标签中的两个 JavaScript 文件。打开 index.html 并添加以下代码:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>JavaScript Modules</title>
  </head>

  <body>
    <h1>Answers</h1>
    <h2><strong id="x"></strong> and <strong id="y"></strong></h2>

    <h3>Addition</h3>
    <p id="addition"></p>

    <h3>Subtraction</h3>
    <p id="subtraction"></p>

    <h3>Multiplication</h3>
    <p id="multiplication"></p>

    <h3>pision</h3>
    <p id="pision"></p>

    <script src="functions.js"></script>
    <script src="script.js"></script>
  </body>
</html>

这个页面很简单,就不详细说明了。

functions.js 文件中包含将会在第二个脚本中用到的数学函数。打开文件并添加以下内容:

functions.js

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

function difference(x, y) {
  return x - y
}

function product(x, y) {
  return x * y
}

function quotient(x, y) {
  return x / y
}

最后,script.js 文件用来确定 x 和 y 的值,以及调用前面那些函数并显示结果:

script.js

const x = 10
const y = 5

document.getElementById('x').textContent = x
document.getElementById('y').textContent = y

document.getElementById('addition').textContent = sum(x, y)
document.getElementById('subtraction').textContent = difference(x, y)
document.getElementById('multiplication').textContent = product(x, y)
document.getElementById('pision').textContent = quotient(x, y)

保存之后在浏览器中打开 index.html 可以看到所有结果:

1.png

对于只需要一些小脚本的网站,这不失为一种有效的组织代码的方法。但是这种方法存在一些问题:

  • 污染全局命名空间:你在脚本中创建的所有变量(sum、 difference 等)现在都存在于 window 对象中。如果你打算在另一个文件中使用另一个名为 sum 的变量,会很难知道在脚本的其它位置到底用的是哪一个值变量,因为它们用的都是相同的 window.sum 变量。唯一可以使变量私有的方法是将其放在函数的作用域中。甚至在 DOM 中名为 x 的 id 可能会和 var x 存在冲突。
  • 依赖管理:必须从上到下依次加载脚本来确保可以使用正确的变量。将脚本分别保存存为不同文件会产生分离的错觉,但本质上与放在页面中的单个 <script> 中相同。

在 ES6 把原生模块添加到 JavaScript 语言之前,社区曾经尝试着提供了几种解决方案。第一个解决方案是用原生 JavaScript 编写的,例如将所有代码都写在 objects 或立即调用的函数表达式(IIFE)中,并将它们放在全局命名空间中的单个对象上。这是对多脚本方法的一种改进,但是仍然存在将至少一个对象放入全局命名空间的问题,并没有使在第三方之间一致地共享代码的问题变得更加容易。

之后又出现了一些模块解决方案:CommonJS 是一种在 Node.js 实现的同步方法,异步模块定义(AMD)是一种异步方法,还有支持前面两种样式的通用方法——通用模块定义(UMD)。

这些解决方案的出现使我们可以更轻松地以的形式共享和重用代码,也就是可以分发和共享的模块,例如 npm。但是由于存在许多解决方案,并且都不是 JavaScript 原生的,所以需要依靠 Babel、Webpack 或 Browserify之类的工具才能在浏览器中使用。

由于多文件方法存在许多问题,并且解决方案很复杂,所以开发人员对把模块化开发的方法引入 JavaScript 语言非常感兴趣。于是 ECMAScript 2015 开始支持 JavaScript module

module 是一组代码,用来提供其他模块所使用的功能,并能使用其他模块的功能。 export 模块提供代码,import 模块使用其他代码。模块之所以有用,是因为它们允许我们重用代码,它们提供了许多可用的稳定、一致的接口,并且不会污染全局命名空间。

模块(有时称为 ES 模块)现在可以在原生 JavaScript 中使用,在本文中,我们一起来探索怎样在代码中使用及实现。

原生 JavaScript 模块

JavaScript 中的模块使用import 和 export 关键字:

  • import:用于读取从另一个模块导出的代码。
  • export:用于向其他模块提供代码。

接下来把前面的的 functions.js 文件更新为模块并导出函数。在每个函数的前面添加 export 。

functions.js

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

export function difference(x, y) {
  return x - y
}

export function product(x, y) {
  return x * y
}

export function quotient(x, y) {
  return x / y
}

在 script.js 中用 import 从前面的 functions.js 模块中检索代码。

注意import 必须始终位于文件的顶部,然后再写其他代码,并且还必须包括相对路径(在这个例子里为  ./)。

把 script.js 中的代码改成下面的样子:

script.js

import { sum, difference, product, quotient } from './functions.js'

const x = 10
const y = 5

document.getElementById('x').textContent = x
document.getElementById('y').textContent = y

document.getElementById('addition').textContent = sum(x, y)
document.getElementById('subtraction').textContent = difference(x, y)
document.getElementById('multiplication').textContent = product(x, y)
document.getElementById('pision').textContent = quotient(x, y)

注意:要通过在花括号中命名单个函数来导入。

为了确保代码作为模块导入,而不是作为常规脚本加载,要在 index.html 中的 script 标签中添加type="module"。任何使用 import 或 export 的代码都必须使用这个属性:

index.html

<script 
  type="module" src="functions.js">
</script>
<script 
  type="module" src="script.js">
</script>

由于受限于 CORS 策略,必须在服务器环境中使用模块,否则会出现下面的错误:

Access to script at 'file:///Users/your_file_path/script.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

模块与常规脚本不一样的地方:

  • 模块不会向全局(window)作用域添加任何内容。
  • 模块始终处于严格模式。
  • 在同一文件中把同一模块加载两次不会出问题,因为模块仅执行一次
  • 模块需要服务器环境。

模块仍然经常与打包程序(如 Webpack)一起配合使用,用来增加对浏览器的支持和附加功能,但它们也可以直接用在浏览器中。

接下来探索更多使用 import 和 export 语法的方式。

命名导出

如前所述,使用 export 语法允许你分别导入按名称导出的值。以这个 function.js 的简化版本为例:

functions.js

export function sum() {}
export function difference() {}

这样允许你用花括号按名称导入 sum 和 difference

script.js

import {sum, difference} from './functions.js'

也可以用别名来重命名该函数。这样可以避免在同一模块中产生命名冲突。在这个例子中,sum 将重命名为 add,而 difference 将重命名为 subtract

script.js

import {
  sum as add,
  difference as subtract
} from './functions.js'

add(1, 2) // 3

在这里调用 add() 将产生 sum() 函数的结果。

使用 * 语法可以将整个模块的内容导入到一个对象中。在这种情况下,sum 和 difference 将成为 mathFunctions 对象上的方法。

script.js

import * as mathFunctions from './functions.js'

mathFunctions.sum(1, 2) // 3
mathFunctions.difference(10, 3) // 7

原始值、函数表达式和定义、异步函数、类和实例化的类都可以导出,只要它们有标识符就行:

// 原始值
export const number = 100
export const string = 'string'
export const undef = undefined
export const empty = null
export const obj = {name: 'Homer'}
export const array = ['Bart', 'Lisa', 'Maggie']

// 函数表达式
export const sum = (x, y) => x + y

// 函数定义
export function difference(x, y) {
  return x - y
}

// 匿名函数
export async function getBooks() {}

// 类
export class Book {
  constructor(name, author) {
    this.name = name
    this.author = author
  }
}

// 实例化类
export const book = new Book('Lord of the Rings', 'J. R. R. Tolkein')

所有这些导出都可以成功被导入。接下来要探讨的另一种导出类型称为默认导出。

默认导出

在前面的例子中我们导出了多个命名的导出,并分别或作为一个对象导入了每个导出,将每个导出作为对象上的方法。模块也可以用关键字 default 包含默认导出。默认导出不使用大括号导入,而是直接导入到命名标识符中。

以 functions.js 文件为例:

functions.js

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

在 script.js 文件中,可以用以下命令将默认函数导入为 sum

script.js

import sum from './functions.js'

sum(1, 2) // 3

不过这样做很危险,因为在导入过程中对默认导出的命名没有做任何限制。在这个例子中,默认函数被导入为 difference,尽管它实际上是 sum 函数:

script.js

import difference from './functions.js'

difference(1, 2) // 3

所以一般首选使用命名导出。与命名导出不同,默认导出不需要标识符——原始值本身或匿名函数都可以用作默认导出。以下是用作默认导出的对象的示例:

functions.js

export default {
  name: 'Lord of the Rings',
  author: 'J. R. R. Tolkein',
}

可以用以下命令将其作为 book 导入:

functions.js

import book from './functions.js'

同样,下面的例子演示了如何将匿名箭头函数导出为默认导出:

functions.js

export default () => 'This function is anonymous'

可以这样导入:

script.js

import anonymousFunction from './functions.js'

命名导出和默认导出可以彼此并用,例如在这个模块中,导出两个命名值和一个默认值:

functions.js

export const length = 10
export const width = 5

export default function perimeter(x, y) {
  return 2 * (x + y)
}

可以用以下命令导入这些变量和默认函数:

script.js

import calculatePerimeter, {length, width} from './functions.js'

calculatePerimeter(length, width) // 30

现在默认值和命名值都可用于脚本了。

总结

模块化编程设计允许我们把代码分成单个组件,这有助于代码重用,同时还可以保护全局命名空间。一个模块接口可以在原生 JavaScript 中用关键字 import 和 export 来实现。

原文地址:https://www.taniarascia.com/javascript-modules-import-export/

作者:Tania Rascia

更多编程相关知识,请访问:编程学习!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javascript中的modules、import和export 的相关文章

  • 无法在 JavaScript for 循环中读取 null 的属性“长度”

    我正在尝试制作一个像 Stack Overflow 那样的 Markdown 编辑器 如果我实际上没有在文本区域中键入星号和包含短语的 http 我会收到标题中列出的此错误 如果我只输入包含星号的短语 则错误指的是这一行 if linkif
  • pubnub 和 head.js

    有没有人成功整合过pubnub http www pubnub com 和 head js 正确吗 Pubnub http www pubnub com 希望我将他们的脚本放在页面底部并带有 div 就在它前面的标签 这可以确保在最后调用
  • 使用 javascript 更改 div 颜色

    div style height 20px width 100 background color 000000 div br
  • ajaxStop() 不触发

    这是不起作用的代码 document ajaxStop function this unbind ajaxStop prevent running again when other calls finish Display everythi
  • 仅单击 div 内部

    我正在为一个小网站制作教程 我只想让教程气泡可点击 因此 当我们尝试单击气泡之外的某些内容时 什么也不会发生 换句话说 我希望我的 html 不可点击 而 tutorial bubble 可点击 尝试这个 jQuery function h
  • 打开 md-calendar 时滚动到当前日期

    目前正在构建一个使用 Angular Material 的应用程序 我们需要一个 md calendar 组件 我们想要自定义按钮样式和内容 因此不使用普通的 md datepicker 问题是 当 md calender 打开时 滚动位置
  • 了解 sort() 比较函数

    我正在使用一个电子商务平台 该平台无法重新排序产品属性字段的选项 这真的很糟糕 因为要插入新选项 您几乎必须删除所有现有选项并重新开始 我正在尝试在客户端进行操作 这是我正在处理的内容 这是针对鞋码的 9 EE 9 1 2 EE 10 EE
  • Chrome 扩展同步调用 - 仅在窗口关闭后创建窗口

    我有这个代码 function voteNewWindow mailNum chrome windows create url http www google com incognito true function window conso
  • 将文本大小调整为矩形 在 Canvas HTML5 中调整大小

    我是 Canvas 新手 我正在创建一个网站 以在调整矩形大小时增加文本 我尝试了很多 但没有任何效果 实际上 我希望如果我仅按其宽度调整矩形大小 向左拉伸 向右拉伸 则仅应增加文本宽度而不是字体大小 我已经完成了字体大小 但发现增加孤立文
  • 判断一个数字是否能被 3 或 5 整除 (FizzBu​​zz)

    如何根据输出是否能被 3 或 5 整除来更改输出 如果它能被 3 整除 我想显示 rock 如果它能被 5 整除 我想显示 star 类似于 FizzBu zz 如果两者都有 他们都会看到 这是我的代码 if var n Math floo
  • 循环遍历元素并逐步为每个元素应用 CSS 规则

    我有一个网格布局 每个网格布局中都有不同数量的元素 我想动态添加内联grid column通过循环遍历 div 中存在的每个元素的 CSS 规则 ul 与一类 list 所以 HTML 代码的输出需要是 ul class list ul u
  • 如何从 JSON 响应重定向?

    所以我尝试使用 Flask 和 Javascript 上传器 Dropzone 上传文件并在上传完成后重定向 文件上传正常 但在烧瓶中使用传统的重定向 return redirect http somesite com 不执行任何操作 页面
  • console.log() 显示同一对象属性的矛盾值

    我想我可能要疯了 我使用 console log 来查看对象的状态 然后在下一行对同一对象的特定属性执行 console log 并为每个属性获取不同的值 我正在使用的代码是 console log this pictures Items
  • ToggleClass 动画 jQuery?

    我的网站上有一个部分 当用户单击时我希望它展开 我正在使用 jQuerytoggleClass为了这 expandable function e e preventDefault this closest article toggleCla
  • Google 地图 API:忽略 DirectionService 请求中的季节性限制

    我目前正在开发一张地图 其中显示两点之间的最短路线 使用不同的交通工具 我注意到 有时 例如在冬季关闭的道路不会被考虑在内 我发现我可以使用方向服务 下面的代码 忽略高速公路 收费站和渡轮 但我一生都无法弄清楚如何 是否可以忽略季节性限制
  • 如何打开弹出窗口并用父窗口中的数据填充它?

    如何使用 JavaScript jQuery 使用父页面中 JS 变量的数据填充弹出窗口 在我的示例中 我有一个文件名数组 我在父窗口中最多列出五个 如果还有更多 我想提供一个链接来打开弹出窗口并列出数组中的每个帖子 因此 如果我打开一个包
  • 禁用特定 div 上的 Tab 键

    我有以下结构 div div Some content div div Some content div div 我想 禁用 div2 上的 tab 键 我的意思是按下 tab 键时 div2 的元素不会获得焦点 有没有简单的方法可以使用
  • 如何处理requireJs超时错误?

    我正在使用 require js 作为加载框架编写一个移动混合应用程序 我遇到加载错误的问题 我想做的是在设备离线且无法下载在屏幕上显示地图所需的 google 地图 API 脚本时设置后备解决方案 我得到的只是 Uncaught Erro
  • Knockout.js 安全绑定

    我想使用带有淘汰赛的安全绑定 为此我使用敲除安全绑定 js https github com brianmhunt knockout secure binding 谁能解释一下为什么下面的代码不起作用 它会抛出一个错误 未捕获 淘汰 安全
  • 尝试在 React 应用程序中连接到 MySQL 数据库时,无法读取未定义的属性(读取“查询”)错误

    我正在尝试连接到 MySQL 数据库并在单击按钮后在 React 应用程序中运行查询 一些它如何给出错误 我当前的代码如下所示 import mysql from mysql function App async function sync

随机推荐

  • vue+webpack2实现路由懒加载的方法介绍

    下面Vue js教程栏目给大家介绍一下vue 43 webpack2实现路由的懒加载的方法 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 当打包构建应用时 xff0c Javascript 包会变得
  • JS Math对象的10 个实用方法

    推荐教程 xff1a JavaScript视频教程 JavaScript中的math 对让我们能够对执行一些数学操作 它具有数学常数和函数的属性和方法 在今天的文章中将介绍 Math对象的一些有用方法 1 Math min Math min
  • PDF文档电子公章的初试

    PART 1 大家在日常生活中经常会接触到电子公章 xff0c 比如电子发票上一般会包含电子公章信息 xff0c 比如下图发票中就带有两个电子公章 xff0c 顶部的公章是普通的图形公章 xff0c 右下角的电子公章不仅包含图形公章还包含了
  • css grid构建复杂布局的小技巧

    xff08 推荐教程 xff1a CSS教程 xff09 网格布局是现代CSS中最强大的功能之一 使用网格布局可以帮助我们在没有任何外部 UI 框架的情况下构建复杂的 快速响的布局 在这篇文章中 xff0c 将会介绍所有我们需要了解的 CS
  • vue.js中使用v-for以及获取索引的方法介绍

    下面Vue js教程栏目带大家了解一下vue js中v for的使用及索引获取 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 2 x版本 xff1a v for 61 34 item index i
  • HTML网页自动跳转的5种方法

    xff08 推荐教程 xff1a html教程 xff09 在我们进行网站创建时经常会遇到需要进行网页跳转的情况 xff0c 本文就来为大家介绍五种网页自动跳转的方法 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望
  • 深入讨论JavaScript中Set对象如何让代码更快

    我确信有很多开发人员坚持使用基本的全局对象 xff1a 数字 xff0c 字符串 xff0c 对象 xff0c 数组和布尔值 对于许多用例 xff0c 这些都是需要的 但是如果想让你的代码尽可能快速和可扩展 xff0c 那么这些基本类型并不
  • ES6中的for ... of循环和可迭代对象

    推荐教程 xff1a JavaScript视频教程 本文将研究 ES6 的 for of 循环 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 旧方法 在过去 xff0c 有两种方法可以遍历 java
  • 8个编写JS代码的小技巧和窍门

    下面js教程栏目给大家介绍8个编写javascript代码的技巧和窍门 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 推荐教程 xff1a JavaScript视频教程 1 生成指定区间内的数字 有
  • 浅谈css z-index应用

    做过页面布局的同学对z index属性应该是很熟悉了 xff0c z index是针对网页显示中的一个特殊属性 因为显示器是显示的图案是一个二维平面 xff0c 拥有x轴和y轴来表示位置属性 为了表示三维立体的概念如显示元素的上下层的叠加顺
  • jquery中怎样将类数组对象转换为数组对象

    相关推荐 xff1a jQuery视频教程 类数组对象的定义 xff1a 所谓 34 类数组对象 34 就是一个常规的Object对象 xff0c 如 34 p 34 但它和数组对象非常相似 xff1a 具备length属性 xff0c 并
  • 理解对象原型和原型链

    本篇文章带大家介绍一下JavaScript中的对象原型和原型链 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 对象原型 相信大家都这样用过 map xff1a let arr 61 0 1 2 le
  • JavaScript中处理异步的几种方式

    在网站开发中 xff0c 异步事件是项目必然需要处理的一个环节 xff0c 也因为前端框架的兴起 xff0c 通过框架实现的 SPA 已经是快速建构网站的标配了 xff0c 一部获取数据也就成了不可或缺的一环 xff1b 本文来就讲一讲 J
  • 软件测试 | 测试开发 | 一种基于目标检测实现黑花屏分类任务的方案

    背景 视频帧的黑 花屏的检测是视频质量检测中比较重要的一部分 xff0c 传统做法是由测试人员通过肉眼来判断视频中是否有黑 花屏的现象 xff0c 这种方式不仅耗费人力且效率较低 为了进一步节省人力 提高效率 xff0c 一种自动的检测方法
  • VSCode使用Git进行版本控制

    相关推荐 xff1a vscode基础教程 Visual Studio Code 使用Git进行版本控制 本来认为此类教程 xff0c 肯定是满网飞了 今天首次使用VS Code的Git功能 xff0c 翻遍了 所有中文教程 xff0c 竟
  • 使用Llama Logs实时可视化Node错误

    本篇文章给大家介绍一下Node开发神器 Llama Logs xff0c 使用Llama Logs实时可视化Node错误 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 相关推荐 xff1a node
  • JS中的工厂函数和构造函数

    当谈到JavaScript语言与其他编程语言相比时 xff0c 你可能会听到一些令人困惑东西 xff0c 其中之一是工厂函数和构造函数 工厂函数 所谓工厂函数 xff0c 就是指这些内建函数都是类对象 xff0c 当你调用他们时 xff0c
  • 如何使用 map 代替纯 JavaScript 对象?

    JavaScript 普通对象 key 39 value 39 可用于保存结构化数据 但是我发现很烦人的一件事 xff1a 对象的键必须是字符串 xff08 或很少使用的符号 xff09 如果用数字作键会怎样 xff1f 在这种情况下没有错
  • 深入浅析Service Workers

    本篇文章给大家介绍一下JavaScript API Service Workers 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 相关推荐 xff1a 编程入门 service worker 是什么
  • javascript中的modules、import和export

    在互联网的洪荒时代 xff0c 网站主要用 HTML和 CSS 开发的 如果将 JavaScript 加载到页面中 xff0c 通常是以小片段的形式提供效果和交互 xff0c 一般会把所有的 JavaScript 代码全都写在一个文件中 x