我刚刚开始研究一个小节点项目,它将与MongoDB接口。然而,我似乎不能正确地导入相关的节点模块,即使我已经通过npm正确地安装了它们。

例如,下面的代码抛出一个错误,告诉我“express没有默认导出”:

import express from "express";

然而,这段代码可以工作:

const express = require("express");

我的问题是,import和variable/require方法的功能有什么不同?我想修复在项目中困扰我的导入的任何问题,因为它似乎可能会导致后续的其他问题。


当前回答

这些工具属于不同的时代。

require只存在于CommonJS中(创建Node.js用于导入和导出应用程序中的模块的方式),import是ES6,即浏览器JavaScript和服务器JavaScript (Node.js)都可以使用的新工具。

除了历史上的差异之外,在使用上也有差异,其中import比所需的更灵活、更现代和更强大。

然而,重要的是要考虑到一些浏览器仍然不支持ES6,因此在使用它之前可能有必要进行编译。

Require使用模块。Exports,这是导出模块的“旧”(但仍然有效)语法,它可以是我们想要的任何东西,一个对象,一个字符串等。

导入两者都使用,即可以使用模块。导出和导出,它允许你像模块一样导出不同的代码段。出口了。进口的好处之一是,它只能进口出口的一部分:

例子:

导出文件:

// A.js file

// CommonJS syntax
module.exports = {
     foo: function(){ return 'bar';},
     baz: 123
}

// ES6 syntax
export function foo(){ return 'bar';}
export const baz = 123;

// or

function foo(){ return 'bar';}
const baz = 123;

export default {foo, baz};

导入文件:

// B.js file

// CommonJS syntax
const A = require('./A.js');
const foo = A.foo;
const baz = A.baz;

// ES6 syntax
import * as A from './A.js';
const foo = A.foo;
const baz = A.baz;

// or only
import {foo, baz} from './A.js';

当您使用导出默认值(ES6语法)时,这意味着每个文件只能导出一个东西。如果它是一个对象,import只能导入片段。但如果它是一个函数,那么你可以使用import foo from './A.js';不需要{}或*作为foo。

来源:https://pt.stackoverflow.com/a/213938/317251

其他回答

这个简单的图像将帮助您理解require和import之间的区别。

除此之外,

使用require时,你不能选择性地只加载你需要的片段,但是使用import时,你可以选择性地只加载你需要的片段,这可以节省内存。

对于require,加载是同步的(一步一步地),另一方面,导入可以是异步的(不需要等待之前的导入),因此它可以比require执行得更好一些。

import来自ES6是对旧CommonJs模块的更新,其中require来自CommonJs模块。接下来,我将区分语法差异但现在,让我们理解他们为什么更新这个。

require是在运行时执行的函数,这意味着它的行为和其他JavaScript函数一样,如果你在脚本中间定义它,脚本的上述部分不会识别它,或者如果你把它放在if语句中,它只会在if表达式为真时执行,或者如果你把它放在另一个函数中,它只会在函数执行时执行,等等。

另一方面,import在静态级别上执行,它有一些规则,它应该总是在根级别上,不应该在任何条件语句或函数中。由于JavaScript对导入进行静态分析,如果您这样做,它将抛出编译时错误。

这些优点是由于团队改变了导入包到ES6的方式。

当ES6更好的时候,node为什么还在使用CommonJs模块?

节点中有大量使用CommonJs模块的代码库,由于对ES6的多年支持,因此很难将其转换为ES6。但是有很多工具可以让我们在node中编写ES6代码,但是这些工具会把它转译成CommonJs。

语法差异:

Import完全取决于从包装中导出东西的方式。

如果在导出函数或变量时使用默认的导出方式。等模块。export = commondj中的functionName或在ES6中导出默认的functionName,然后导入将如下所示。

在CommonJs vs ES6中导入

const functionName = require("package/exampleFile"); // CommonJs

import functionName from "package/expampleFile.js"; // ES6.
// here you can see that we need to add .js at the end of the file

如果像module一样导出多个函数。在CommonJs中exports = {functionName1, functionName2}或在ES6中export functionName1 export functionName2,那么导入将如下所示。

const {functionName1, functionName2} = require("package/exampleFile"); // CommonJs

import {functionName1, functionName2} from "package/expampleFile.js"; // ES6.

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

大多数人使用babel来编译导入和导出,这使得导入与所需的操作一致。

Node.js的未来版本可能会支持导入本身(实际上,实验版本已经支持了),根据Node.js的说明,导入不支持node_modules,它基于ES6,并且必须指定模块的路径。

所以我建议你不要在babel中使用import,但是这个功能还没有被确认,将来可能会支持node_modules,谁知道呢?


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

假设fileapp_es6.js包含以下导入:

import format from 'date-fns/format';

这是一个从节点包date-fns导入格式函数的指令。

相关的包。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"
                }
            }
        ]
    ]
}

包中定义的构建服务器文件脚本。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);

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

这两者之间有很大的区别:

import express from "express";

这:

import * as express from "express";

从CommonJS到ES6的正确翻译

const express = require("express");

是第二个导入。

基本上,这是因为在第一个导入中,您在express模块中寻找名为express的导出。第二个是导入名称为express的整个快速模块。

这些工具属于不同的时代。

require只存在于CommonJS中(创建Node.js用于导入和导出应用程序中的模块的方式),import是ES6,即浏览器JavaScript和服务器JavaScript (Node.js)都可以使用的新工具。

除了历史上的差异之外,在使用上也有差异,其中import比所需的更灵活、更现代和更强大。

然而,重要的是要考虑到一些浏览器仍然不支持ES6,因此在使用它之前可能有必要进行编译。

Require使用模块。Exports,这是导出模块的“旧”(但仍然有效)语法,它可以是我们想要的任何东西,一个对象,一个字符串等。

导入两者都使用,即可以使用模块。导出和导出,它允许你像模块一样导出不同的代码段。出口了。进口的好处之一是,它只能进口出口的一部分:

例子:

导出文件:

// A.js file

// CommonJS syntax
module.exports = {
     foo: function(){ return 'bar';},
     baz: 123
}

// ES6 syntax
export function foo(){ return 'bar';}
export const baz = 123;

// or

function foo(){ return 'bar';}
const baz = 123;

export default {foo, baz};

导入文件:

// B.js file

// CommonJS syntax
const A = require('./A.js');
const foo = A.foo;
const baz = A.baz;

// ES6 syntax
import * as A from './A.js';
const foo = A.foo;
const baz = A.baz;

// or only
import {foo, baz} from './A.js';

当您使用导出默认值(ES6语法)时,这意味着每个文件只能导出一个东西。如果它是一个对象,import只能导入片段。但如果它是一个函数,那么你可以使用import foo from './A.js';不需要{}或*作为foo。

来源:https://pt.stackoverflow.com/a/213938/317251