Разница между "require(x)" и "import x"
Я только начал работать над небольшим проектом на Node.js, который будет взаимодействовать с MongoDB. Однако у меня возникают проблемы с импортом необходимых модулей Node, хотя я корректно установил их с помощью npm
.
Например, следующий код вызывает ошибку, сообщающую о том, что "express не имеет экспортируемого по умолчанию":
import express from "express";
Тем не менее, этот код работает:
const express = require("express");
Таким образом, мой вопрос: в чем разница между методами импорта и использования require? Я хотел бы исправить проблемы с импортами в проекте, так как это может вызвать дополнительные проблемы в будущем.
5 ответ(ов)
Чтобы упростить понимание:
- Import и Export — это функции ES6 (JavaScript следующего поколения).
- Require — это традиционный способ импорта кода из других файлов.
Основное различие заключается в том, что при использовании require весь файл JavaScript загружается или включается полностью, даже если вам не нужны некоторые его части.
var myObject = require('./otherFile.js'); // Этот JS файл будет загружен полностью.
В то время как с помощью import вы можете извлекать только те объекты/функции/переменные, которые вам нужны:
import { getDate } from './utils.js';
// Здесь я импортирую только метод getDate из файла, вместо того чтобы загружать весь файл.
Кроме того, важным различием является то, что вы можете использовать require в любом месте программы, тогда как import должен располагаться в начале файла.
Правка: В последних версиях Node.js вы также можете использовать деструктуризацию. Это будет выглядеть так:
const { getDate } = require('./date.js');
В JavaScript ES6 для импорта и экспорта переменных, массивов и объектов между файлами следует использовать ключевые слова import
и export
. Вот пример:
Новый подход (ES6):
// В файле otherFile.js
export default myObject;
// В другом файле
import myObject from './otherFile.js';
Старый подход:
В старых версиях JavaScript используется конструкция require
и module.exports
. Пример:
// В файле otherFile.js
module.exports = myObject;
// В другом файле
var myObject = require('./otherFile.js');
Таким образом, с переходом на ES6 вы получаете более современные и удобные синтаксис и возможности для работы с модулями.
Существует значительная разница между этими двумя способами импорта:
import express from "express";
и
import * as express from "express";
Правильный перевод из CommonJS в ES6 для
const express = require("express");
это второй вариант импорта.
Дело в том, что в первом варианте вы ищете экспорт в модуле express
, который называется express
. Во втором же случае вы импортируете весь модуль express
и присваиваете ему имя express
.
Эти инструменты принадлежат к разным поколениям.
require
существует только в CommonJS (это способ, который Node.js использует для импорта и экспорта модулей внутри приложения), тогда как import
— это ES6, то есть новый инструмент, который может использоваться как в JavaScript браузеров, так и в серверном JavaScript (Node.js).
Кроме этой исторической разницы, существуют и различия в использовании, где import
более гибок, современен и мощен по сравнению с require
.
Важно отметить, что некоторые браузеры все еще не поддерживают ES6, поэтому может потребоваться компиляция перед использованием.
require
использует module.exports
, что является "старым" (но все еще действительным) синтаксисом для экспорта модуля, который может представлять собой что угодно — объект, строку и т.д.
В то время как import
использует оба подхода, то есть вы можете использовать module.exports
и export
, и он позволяет экспортировать различные части кода более-менее так же, как это делал module.exports
. Одним из преимуществ import
является возможность импортировать только части того, что было экспортировано.
Примеры:
Файл, который экспортирует:
// A.js файл
// Синтаксис CommonJS
module.exports = {
foo: function(){ return 'bar';},
baz: 123
}
// Синтаксис ES6
export function foo(){ return 'bar';}
export const baz = 123;
// или
function foo(){ return 'bar';}
const baz = 123;
export default {foo, baz};
Файл, который импортирует:
// B.js файл
// Синтаксис CommonJS
const A = require('./A.js');
const foo = A.foo;
const baz = A.baz;
// Синтаксис ES6
import * as A from './A.js';
const foo = A.foo;
const baz = A.baz;
// или только
import {foo, baz} from './A.js';
При использовании export default
(синтаксис ES6) подразумевается, что вы экспортируете только одну вещь в файл. Если это объект, import
может импортировать лишь его части. Но если это, например, функция, то вы можете просто использовать import foo from './A.js';
без необходимости использовать {}
или * as foo
.
import
в ES6
является обновлением по сравнению с устаревшим модулем CommonJs
, откуда и взялась конструкция require
. Чуть позже я объясню разницу в синтаксисе, но сейчас давайте разберемся, почему было принято это обновление.
Функция require
выполняется во время исполнения, что означает, что она ведет себя как другие функции JavaScript: если вы определите ее в середине скрипта, то верхняя часть скрипта не сможет ее распознать, или если вы поместите ее внутри условного оператора, она выполнится только в случае истинности выражения, или если вы поместите ее внутри другой функции, то она выполнится только тогда, когда эта функция будет вызвана и так далее.
С другой стороны, import
выполняется на статическом уровне и имеет свои правила: он должен находиться на корневом уровне и не должен быть внутри каких-либо условных операторов или функций. Благодаря статическому анализу JavaScript для импортов, при нарушении этих правил будут выданы ошибки во время компиляции.
Эти преимущества и стали причиной изменения способа импорта пакетов на ES6
.
Почему же Node все еще использует модуль CommonJs, если ES6 лучше?
Существует огромная база кода, использующая модуль CommonJs в Node, и преобразовать ее в ES6 очень сложно, так как она поддерживается уже много лет. Однако существуют различные инструменты, которые позволяют писать код на ES6 в Node, но в конечном итоге эти инструменты транслируют его в CommonJs.
Различия в синтаксисе:
Импорт полностью зависит от того, как происходил экспорт из пакета.
Если используется стандартный способ экспорта функции или переменной, например, module.export = functionName
в CommonJs
или export default functionName
в ES6
, тогда импорты будут выглядеть так:
Импорт в CommonJs против ES6
const functionName = require("package/exampleFile"); // CommonJs
import functionName from "package/exampleFile.js"; // ES6.
// здесь вы можете видеть, что необходимо добавлять .js в конце имени файла
Если экспортируется несколько функций, как module.exports = {functionName1, functionName2}
в CommonJs
или export functionName1; export functionName2;
в ES6
, тогда импорт будет следующим:
const {functionName1, functionName2} = require("package/exampleFile"); // CommonJs
import {functionName1, functionName2} from "package/exampleFile.js"; // ES6.
Как в Node.js "подключить" функции из других файлов?
TypeScript ошибка TS2304: не удается найти имя 'require'
Как запустить файлы TypeScript из командной строки?
Неизвестное расширение файла ".ts" для файла TypeScript
Как проверить, содержит ли массив строку в TypeScript?