latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

Flow.js Ver 1.0.1 リリース と (this.self || global) の解説

Flow.js Version 1.0.1 をリリースしました。

使い方はこちらをごらんください
http://www.slideshare.net/uupaa/flowjs

リポジトリはこちらです
https://github.com/uupaa/flow.js

$ npm install flow_js でもインストールできます

既にインストールしている方は、
$ npm update flow_js でupdateできます。

主な改善は、

  • FlowのargsをJunctionに引き継いでいなかったので引き継ぐようにしました
var Flow = require("flow_js").Flow;

var junction = new Flow(2, function(err, args) {
  // この場合の args は = [ [1,4], [2,3] ] です。
  // Array.prototype.concat.apply([], args).sort() で、 平滑化し [1,2,3,4] として取り出します

  var values = Array.prototype.concat.apply([], args).sort();
  console.log(values); // -> "1,2,3,4"
});

new Flow(2, junction).pass(1).pass(4);
new Flow(2, junction).pass(2).pass(3);
  • Junction(合流)はあるが、fork(分岐)機能がなかったため実装しました
var Flow = require("flow_js").Flow;

// Date.now() % 2 の 結果により o_o または o_O に分岐します
var flows = {
  o_o: function() { console.log("o_o"); },
  o_O: function() { console.log("o_O"); }
};
var flow = new Flow(2, flows);
Date.now() % 2 ? flow.fork("o_O").pass()
               : flow.fork("o_o").pass();
  • global.Flow がある場合は上書きしないようにしました

// Flow.js version 1.0.0
(function(global) {

// --- export ----------
if (typeof module !== "undefined") {
    module.exports = { Flow: Flow };
}
global.Flow = Flow;

})(this.self || global);
// Flow.js version 1.0.1
(function(global) {

// --- export ----------
if (typeof module !== "undefined") { // is modular
    module.exports = { Flow: Flow };
}
global.Flow || (global.Flow = Flow); // 既に global.Flow があったらエクスポートしない

})(this.self || global);

ソースコード末尾の (this.self || global) について

// Flow.js version 1.0.1
(function(global) {
// --- header ----------
function Flow() {}
// --- export ----------
if (typeof module !== "undefined") { // is modular
    module.exports = { Flow: Flow };
}
global.Flow || (global.Flow = Flow);

})(this.self || global);
結論

結論から先に言うと、
「(this || global) ではなく (this.self || global) としているのは、node.js でショートハンドできるから」です。

まず

Flow.js が node.js で動作するときは、(this.self || global) は (undefined || global) と評価されます。

ブラウザで動作するときは、(this.self || global) は (window || undefined) と評価されます(ブラウザ では window.self === window です)。

WebWorkersで動作するときは、(this.self || global) は (WorkerGlobalScope || undefined) と評価されます。

node, browser, webworker などの多様な環境で動作するコードを書くには、これが基本の形になるのかな? と思っています。

(ε・◇・)з o O ( ボクが勝手に言ってるだけです

次に

global.Flow = Flow; を行うことで、グローバル空間に、Flow がエクスポートされます。
ブラウザには require() がないため、global.Flow = Flow; が必須です。

また、node.js 環境では、global.Flow = Flow; があることで、
var Flow = require("flow_js").Flow; とせず、require("flow_js"); とタイプするだけで global.Flow が利用可能になります。

「node環境では、global.Flow = Flow; とすると、global空間に自動的にエクスポートされるが、これが悪さをするケースは(実際には)ほとんどないだろう」「ちょっと試したい時に、短く書ける方法があっても良いのでは」と考えました。

(ε・◇・)з o O ( 業務用途なら、ちゃんと var Flow = require("flow_js").Flow; って書いてくださいね

AMD 対応は?

http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition

(ε・◇・)з o O ( いらないかなと

var self = this; が いけてない理由

ブラウザでは window.self は実質的に予約語です(ESの予約語一覧にはのってないけど)。
WebWorkers だと self は予約語です。
そのような状態ですので、node.jsとブラウザで両刀なjsを書こうとしたら node.js においても self という変数名の利用は好ましくない習慣といえます。
that を使いましょう。

// BAD
var self = this;

function hoge() {
  self.foo();
}
// GOOD
var that = this;

function hoge() {
  that.foo();
}