В чем разница между module.exports
в Node'и export default
в ES6'е? Я пытаюсь понять, почему я получаю ошибку "__ is not a constructor" при попытке export default
в Node.js 6.2.2.
'use strict'
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return 'My name is Slim Shady.'
}
}
// This works
module.exports = SlimShady
'use strict'
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return 'My name is Slim Shady.'
}
}
// This will cause the "SlimShady is not a constructor" error
// if in another file I try `let marshall = new SlimShady()`
export default SlimShady
Проблема заключается в
На момент написания этой статьи ни одна среда не поддерживает модули ES6 нативно. При использовании их в Node.js вам необходимо использовать что-то вроде Babel для преобразования модулей в CommonJS. Но как именно это происходит?
Многие считают, что module.exports = ...
эквивалентно export default ...
, а exports.foo ...
эквивалентно export const foo = ...
. Однако это не совсем так, или, по крайней мере, не так, как это делает Babel.
ES6 default
exports фактически также являются именными exports, за исключением того, что default
- это "зарезервированное" имя, и для него существует специальная синтаксическая поддержка. Давайте посмотрим, как Babel компилирует именованные и стандартные экспорты:
// input
export const foo = 42;
export default 21;
// output
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var foo = exports.foo = 42;
exports.default = 21;
Здесь мы видим, что экспорт по умолчанию становится свойством объекта exports
, как и foo
.
Мы можем импортировать модуль двумя способами: Либо используя CommonJS, либо используя синтаксис ES6 import
.
Ваша проблема: Я полагаю, что вы делаете что-то вроде:
var bar = require('./input');
new bar();
ожидая, что bar
будет присвоено значение экспорта по умолчанию. Но, как видно из примера выше, экспорт по умолчанию присваивается свойству default
!
Поэтому, чтобы получить доступ к экспорту по умолчанию, мы должны сделать следующее
var bar = require('./input').default;
Если мы используем синтаксис модулей ES6, а именно
import bar from './input';
console.log(bar);
Babel преобразует его в
'use strict';
var _input = require('./input');
var _input2 = _interopRequireDefault(_input);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_input2.default);
Вы видите, что каждый доступ к bar
преобразуется в доступ .default
.
tl;dr Сейчас, чтобы это работало, файл, требующий или импортирующий SlimShady
, должен быть скомпилирован с помощью Babel с 'use strict'
.
Я использую babel-cli
6.18.0 в проекте, где я изначально столкнулся с этой ошибкой.
'use strict'
это Bad News Bears.var SlimShady = require('./slim-shady');
var marshall = new SlimShady(); // uh, oh...
'use strict'
import SlimShady from './slim-shady'
var marshall = new SlimShady() // all good in the hood