読者です 読者をやめる 読者になる 読者になる

ぶれすとつーる

だいたいjavascript

Nodeのファイルスコープ

Nodeのファイルスコープについて

JSでスコープを有するものは静的なものでfunction, block、動的スコープではcatch, withとそこそこありますが通常の処理系ではファイルスコープなんてものはないです。

でもNodeではファイル内でvarと宣言した変数はrequireしてもとくにグローバルに漏れずに見かけ上ファイルスコープがあるみたいになってます。

最初これには「おっ?」っておもったんですが、これはこんな感じの実装で実現されてます。

https://github.com/joyent/node/blob/master/src/node.js

  NativeModule.getSource = function(id) {
    return NativeModule._source[id];
  }

  NativeModule.wrap = function(script) {
    return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
  };

  NativeModule.wrapper = [
    '(function (exports, require, module, __filename, __dirname) { ',
    '\n});'
  ];

  NativeModule.prototype.compile = function() {
    var source = NativeModule.getSource(this.id);
    source = NativeModule.wrap(source);

    var fn = runInThisContext(source, this.filename, 0, true);
    fn(this.exports, NativeModule.require, this, this.filename);

    this.loaded = true;
  };

NativeModule.prototype.compileが走るとファイル内のソース文字列を取得(getSource)して無名関数でラップして実行(runInThisContext)されてます。

  NativeModule.wrap = function(script) { // ここでラップしてる
    return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
  };

  NativeModule.wrapper = [ //こいつでラップされてる。
    '(function (exports, require, module, __filename, __dirname) { ',
    '\n});'
  ];

ここでrequireとかmoduleとか__filenameとか__dirnameを渡してるのでファイル内ではこれらの情報にまるでグローバル変数にアクセスするかのように親オブジェクトの指定なしにアクセスできるようになってます。


ドキュメントもよく読んでみるとそれっぽいこと書いてますね。

http://nodejs.jp/nodejs.org_ja/api/globals.html#globals_global_objects

Global Objects

これらのオブジェクトは全てのモジュールで有効です。 これらのオブジェクトのいくつかは実際はグローバルスコープではなくモジュールスコープです - 注意してください。

exports#

現在のモジュールの全てのインスタンス間で共有されるオブジェクトで、 require を通じてアクセス可能になります。 exports は module.exports と同じオブジェクトです。 exports は実際はグローバルではなく、各モジュール毎のローカルです。

require()#

{Function}

require モジュールを指します。モジュール の節を参照してください。 require は実際はグローバルではなく、各モジュール毎のローカルです。

module#

{Object}

現在のモジュールへの参照です。 特に module.exports は exports オブジェクトと同じです。 module は実際はグローバルではなく、各モジュール毎のローカルです。

...


JSのルールを壊さない良い実装だと思います。 :)