ES6 Modules に関する小ネタです。ちょっと言葉では説明しにくいのでコードを見てください。
export var foo = 'Foo';
export var bar = {
changeFoo() {
foo = 'Bar';
}
};
import { foo, bar } from './foobar';
console.log(foo);
bar.changeFoo();
console.log(foo);
babel-node index.js
と実行すると Foo Bar と 出力されます。Foo Foo ではありません。Node.js で CommonJS を書いていた人からすると、???となる挙動ですね。index.js
での foo
はただの変数ではないのです。
CommonJS なら・・・
CommonJS で素直に同じようなモジュールを書こうとすると、以下のようになると思います。これだと当然 Foo Foo と出力されますね。bar.changeFoo()
を呼んでも foobar.js
の module.exports.foo
も更新されませんし、index.js
の foo
も更新されません。
var foo = 'Foo';
module.exports.foo = foo;
var bar = {
changeFoo: function () {
foo = 'Bar';
}
};
module.exports.bar = bar;
var foo = require('./foobar').foo;
var bar = require('./foobar').bar;
console.log(foo);
bar.changeFoo();
console.log(foo);
ES6 Modules の仕様(?)
どうやらこれは ES6 Modules の仕様のようです。仕様のどこに書いてあるかはわからないのですが、Babel でも Traceur でもこういう挙動をするので・・・。
Babel でコンパイルした結果は以下のようになっています。
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var foo = 'Foo';
exports.foo = foo;
var bar = {
changeFoo: function changeFoo() {
exports.foo = foo = 'Bar';
}
};
exports.bar = bar;
'use strict';
var _foobar = require('./foobar');
console.log(_foobar.foo);
_foobar.bar.changeFoo();
console.log(_foobar.foo);
foo は変数ではなく Object の property として参照され、常に値が同期されるようになっていることがわかります。
だからなに?
だからどうだということもないのですが、(そういう設計が良いか悪いかは別として)変更される状態を持つ module を書く場合、以下のように無理に Object にぶら下げなくても
export default {
foo: 123,
bar: 234
};
気軽に直接 export できますね。
export var foo = 123;
export var bar = 234;
おわり。