search
LoginSignup
38

More than 5 years have passed since last update.

posted at

ES6 Modules 間では export/import された変数(?)は同期される

ES6 Modules に関する小ネタです。ちょっと言葉では説明しにくいのでコードを見てください。

foobar.js
export var foo = 'Foo';
export var bar = {
  changeFoo() {
    foo = 'Bar';
  }
};
index.js
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.jsmodule.exports.foo も更新されませんし、index.jsfoo も更新されません。

foobar.js
var foo = 'Foo';
module.exports.foo = foo;
var bar = {
  changeFoo: function () {
    foo = 'Bar';
  }
};
module.exports.bar = bar;
index.js
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 でコンパイルした結果は以下のようになっています。

foobar.js
'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;
index.js
'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;

おわり。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
38