JavaScript
エヴァンゲリオン

エヴァンゲリオンでわかってしまうJavaScript

はじめに

全国1億2000万人のエヴァンゲリオンはわかるけど,JavaScriptはちょっと、、、な皆さんこんにちは。
JavaScriptのプログラミングは、エヴァンゲリオンよりは簡単なのですが、なぜかプログラマにしか浸透しません。

エヴァンゲリオンの諸概念を理解している方であれば、すでにJavaScriptプログラミングは理解していると言っても過言ではありません。

そのあたりをそういうことにして、本編にとりあえず行きましょう。

あわせて読みたい

半年で40kg痩せた!ダイエットでわかるリーンなプロジェクトマネジメント手法

1.地球とミックスイン

まずは、エヴァンゲリオンの世界における地球をJavaScriptで表現してみたいと思います。
ここで登場するのはもちろんエヴァンゲリオン世界のトリックスター、ナディアと我らをつなぐものこと「第一始祖民族」ですよね。

彼らは隕石に「白き月」と「黒き月」を搭載し、地球に向けて放ちました。

要するにファクトリメソッドをもったオブジェクトということになります。
コードで表現するとこんなかんじ。

var theAtlantean = { 
    createBlackMeteor :function(){ 
        return { 
            seedOfHuman : whiteMoon.lilith, 
            whiteMoon : whiteMoon 
        }; 
    }, 
    createWhiteMeteor : function(){ 
        return { 
            seedOfHuman : blackMoon.adam, 
            blackMoon : blackMoon 
        } 
    } 
}; 

このあとは、ファーストインパクトがおこります。
ファーストインパクトでは、原始地球に2つの隕石が衝突して、現在の地球が作られたのは周知の事実ですが、
これは、JavaScriptでいうとmixinにあたります。

mixinはオブジェクトの性質を他のオブジェクトとマージすることで、実現されます。

var mixin = function(objA,objB){ 
    Object.keys(objB).forEach(function(k){ 
        objA[k] = objB[k]; 
    }); 
    return objA; 
}; 

このように実現されます。
このmixinメソッドをつかって、原始地球が現在の地球になる様を表現すると

var theEarth = mixin( previousEarth,theAtlantean.createBlackMeteor()); 
var human     = theEarth.createHuman(); // アダム派性の人類が生まれる 

このようになります。なので、最初theEarthのseedOfHumanプロパティは、blackMoonになるはずでした。
その後、うっかり白き月も衝突するので、

var theEarth = mixin( mixin( previousEarth,theAtlantean.createBlackMeteor()),theAtlantean.createWhiteMeteor());
var human = theEarth.createHuman(); // リリス派生の人類が生まれる 

このようになり、
theEarthのseedOfHumanプロパティは、whiteMoonに書き変わってしまったのです。

mixinはscalaのtraitなどとちがい、名前の衝突を防ぐことはできません。
ですので、mixinされる順番によって動作が変わってしまうことが考えられます。

これは柔軟さでもあるのですが、人類存亡をかけた戦いに少年が巻き込まれるといった事態も考えられるので
注意して利用することが望ましいです。

2. 使徒とコンストラクタ

エヴァンゲリオンに登場するもう一つの人類の形である「使徒」は大きく二つに分類されます。一つはアダム由来のもの、もう一つはリリス由来のものです。

アダムのように「生命の実(S2機関)」を食べたヒトと
リリスのように「知恵の実(知性)」を食べたヒトがいます。

言うまでもないことですが、
これを両方手に入れるとヒトは神になれます。

var TreeOfLife = function(name){ 
    this.name = name; 
    this.hasFruitOfLife = true; 
}; 
var TreeOfIntelligence = function(name){ 
    this.name = name; 
    this.hasFruitOfIntelligence = true; 
}; 
//生命の樹からアダムが 
var adam = new TreeOfLife("ADAM"); 
//知恵の樹からリリスがつくられる 
var lilith = new TreeOfIntelligence("LILITH"); 

そのコンストラクタ(製造者)を取り出して、コピーをつくって
さまざまな使徒がうまれます。

var angels = []; 
angels.push(theEarth.blackMoon.adam); 
angels.push(theEarth.whiteMoon.lilith); 
//アダムが自身を元にいろいろな使徒を生み出す 
//同じ設計図から作られるので、アダム由来の使徒もみなS2機関をもっています。 
with(theEarth.blackMoon){ 
    angels.push(new adam.constructor("SACHIEL")); 
    angels.push(new adam.constructor("SHAMSHEL")); 
    angels.push(new adam.constructor("RAMIEL")); 
    angels.push(new adam.constructor("GAGHIEL")); 
    angels.push(new adam.constructor("ISRAFEL")); 
    angels.push(new adam.constructor("SANDALPHON")); 
    angels.push(new adam.constructor("MATRIEL")); 
    angels.push(new adam.constructor("SAHAQUIEL")); 
    angels.push(new adam.constructor("IREUL")); 
    angels.push(new adam.constructor("LELIEL")); 
    angels.push(new adam.constructor("BARDIEL")); 
    angels.push(new adam.constructor("ZERUEL")); 
    angels.push(new adam.constructor("ARAEL")); 
    angels.push(new adam.constructor("ALMISAEL")); 
    angels.push(new adam.constructor("TABRIS")); 
} 
//最後にリリス由来の人類が使徒として追加される。 
//リリスと同じものを使うので知恵をもっています。 
angels.push(new theEarth.seedOfHuman.constructor("HITO")); 

3.綾波レイとマルドゥック機関

このように製造者を抽出して、同じものを作るということはJavaScriptの特徴でもあります。
同じものといっても、まったく同じものではないというのは綾波レイを思い返しても理解できると思います。

綾波レイは、碇(綾波)ユイのDNAもとに造られているので
次のようになります。

var rei = new yui.constructor; 
//一人目の綾波は 
rei.said = "バァさんは用済み";
//と言っていました。しかし、バァさんに殺されてしまったので 
rei = new yui.constructor;
//別のコピーに置き換えたので、 

console.log(rei.said); // undefined;
//となります。 
rei.said = "ぽかぽかする";

おなじく、次のレイが何か経験しても

rei = new yui.constructor;
されるたびに、その後書き変わったプロパティは元に戻ってしまいます。

ところで、綾波レイにはリリスの魂が入っていますよね。魂の入っていないレイは、ただの肉人形にすぎません。
これはたくさんのリソースプールの中から、一つだけインスタンスを確保するというデザインパターンが適応されています。

コードにすると次のような感じです。

var Mardock = (function(){ 
    var poolOfBodies = []; 
    for (var i = 0;i<10;i++){ 
        poolOfBodies.push(new yui.constructor); 
    }; 

    var _create = function (){ 
        // プールのうち、一つでも魂をもっていたら生成に失敗する 
        if(poolOfBodies.any(function(body){ return !!body.soul})){ 
            throw NoIncarnationError; 
        } 
        var child = poolOfBodies[0]; //最初の要素に魂を渡して、返す。 
        return child.soul = lilith.getSoul(); 
    }; 
    var _release = function(body){ 
        for (var i = 0,length = poolOfBodies.length;i<length;i++){ 
            if( body === poolOfBodies[i] ){ 
                poolOfBodies.splice(i,1); //要素を取り除く 
                return true; 
            } 
        } 
        ; 
    }; 
    // エクスポート 
    return { 
        create : _create, 
        release : _release 
    }; 
})(); 

このようにすると

//リリスの魂をもったレイがつくれる。 
var rei = Mardock.create(); 
var rei2 = Mardock.create();// throws NoIncarnationError 受肉失敗エラー 
Mardock.release(rei);//レイが死ぬ 

var rei3 = Mardock.create();//新しいレイが作れる 

いかがでしたでしょうか。
このように身近なエヴァンゲリオンに例えるだけでJavaScriptが一段と理解しやすくなった気がしませんか?
しませんよね、さようなら。