“ require(x)”和“ import x”之间的区别


190

我刚刚开始研究将与MongoDB交互的小型节点项目。但是,即使我通过正确安装了它们,我似乎也无法正确导入相关的节点模块npm

例如,以下代码引发错误,告诉我“ express没有默认导出”:

import express from "express";

但是,此代码有效:

const express = require("express");

所以我的问题是,导入方法和变量/请求方法的功能有何不同?我想修复困扰该项目的任何进口商品,因为这似乎可能会导致其他问题。


除非您包括express的类型定义,否则第一种形式将没有意义-在这种情况下,您可以使用第二种形式,但是变量express将是type any。您可以在此处包含定义npmjs.com/package/@types/express
Filipe Sabella

Answers:


224

这个简单的图表,可以帮助我理解之间的差异requireimport

在此处输入图片说明

除此之外,

不能选择性地仅加载所需的零件,require而使用imports,则可以仅选择性地加载所需的零件。这样可以节省内存。

另一方面,加载是同步的(分步进行),require因为它import可以是异步的(无需等待先前的导入),因此执行 起来会比更好require


影响代码的最大区别是CommonJS模块中的导出是“计算”的,而ESM模块中的导出是静态的(预定义)。JS只需解析代码(尚未运行)即可确定ESM模块中的导出。在commonJS模块中,仅在模块实际运行时才知道导出,并且您会module.exports在模块初始化代码完成运行时看到分配的内容。在试图使单个模块对ESM和CommonJS都起作用时,仅此差异就造成了兼容性方面的麻烦。
jfriend00

ESM模块对捆绑器更友好,但对编码器的限制更大,因为您无法在ESM模块中计算导出。
jfriend00

76

require和之间的主要区别import是,require它将自动扫描node_modules以查找模块,但是import来自ES6的则不会。

大多数人使用巴贝尔来编译importexport,这使得import行为一样require

Node.js的未来版本可能会import自我支持(实际上,实验版本已经支持),根据Node.js的注释判断,它import不支持node_modules,它基于ES6,并且必须指定模块的路径。

因此,我建议您不要import与babel一起使用,但是此功能尚未得到证实,node_modules将来可能会支持,谁知道呢?


作为参考,下面是babel如何将ES6的import语法转换为CommonJS的require语法的示例。

假设文件app_es6.js包含此导入:

import format from 'date-fns/format';

这是从节点程序包date-fns导入format函数的指令。

相关package.json文件可能包含以下内容:

"scripts": {
    "start": "node app.js",
    "build-server-file": "babel app_es6.js --out-file app.js",
    "webpack": "webpack"
}

相关.babelrc文件可能是这样的:

{
    "presets": [
        [
            "env",
            {
                "targets":
                {
                    "node": "current"
                }
            }
        ]
    ]
}

文件中build-server-file定义的此脚本package.json是babel解析app_es6.js文件并输出文件的指令app.js

运行build-server-file脚本后,如果打开app.js并查找date-fns导入,您将看到它已转换为以下形式:

var _format = require("date-fns/format");

var _format2 = _interopRequireDefault(_format);

对于大多数人来说,该文件大多数都是鬼话,但计算机可以理解。


另外,作为参考,作为如何创建模块并将其导入到项目中的示例,如果安装date-fns然后打开,则node_modules/date-fns/get_year/index.js可以看到它包含:

var parse = require('../parse/index.js')

function getYear (dirtyDate) {
  var date = parse(dirtyDate)
  var year = date.getFullYear()
  return year
}

module.exports = getYear

使用上面的babel流程,您的app_es6.js文件将包含:

import getYear from 'date-fns/get_year';

// Which year is 2 July 2014?
var result = getYear(new Date(2014, 6, 2))
//=> 2014

通天塔将进口转换为:

var _get_year = require("date-fns/get_year");

var _get_year2 = _interopRequireDefault(_get_year);

并相应地处理对该函数的所有引用。


啊啊啊啊啊 Babel尚未安装在此特定项目上,这一切都说得通。我以为ES6导入/导出已经可以正常工作了,但是现在我知道Babel还是将所有内容都进行require了更改
奥斯丁大规模(Austinthemassive)

坚持要求。您以后可以随时对其进行更改,不会遇到任何问题
Juan

1
import won't support node_modules那是什么意思
PrivateOmega

11

让我举一个包含require&import的Express模块​​示例

-要求

var express = require('express');

-进口

import * as  express from 'express';

因此,在使用上述任何语句之后,我们将获得一个名为“ express”的变量。现在我们可以将“ app”变量定义为

var app = express(); 

因此,我们将'require'与'CommonJS'结合使用,并将'import'与'ES6'结合使用。

有关“要求”和“导入”的更多信息,请阅读以下链接。

要求- 在需要的Node.js模块:一切你需要知道的

import- Node.js中的ES6模块更新


3

在这里没有答案,更像是评论,对不起,但我无法评论。

在节点V10中,您可以使用该标志--experimental-modules告诉Nodejs您要使用import。但是您的输入脚本应以结尾.mjs

请注意,这仍然是实验性的事情,不应在生产中使用。

// main.mjs
import utils from './utils.js'
utils.print();
// utils.js
module.exports={
    print:function(){console.log('print called')}
}

参考1-Node.js文档

参考2-github问题


3

新的ES6:

'import'应该与'export'关键字一起使用,以在js文件之间共享变量/数组/对象:

export default myObject;

//....in another file

import myObject from './otherFile.js';

老派

'require'应该和'module.exports'一起使用

 module.exports = myObject;

//....in another file

var myObject = require('./otherFile.js');
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.