ネーミングスペースとしての関数内部変数へのアクセス方法


関数をネーミングスペースにするのは、現在のjavascriptプログラミングで非常に一般的です.コードを1つの関数に含めると、コードに含まれる変数と関数は、関数を含むローカル、またはローカルであり、グローバルな役割ドメインを乱すことはありません.

var value = (function() {  // Wrapper function creates a local scope or namespace
    // your code goes here
    return value;  // Export a value from the namespace
})());  // Invoke the wrapper function to run your code

たとえば、XMLHttpRequestで文字列形式のjavascriptコードを取得したばかりだとします.このコードを実行するつもりです.ネーミングスペースでこのコードを実行したいかもしれません.これにより、コードを実行する過程でグローバルな変数や関数が生成されません.
これは簡単です.実行前にこのコードを関数に含めるだけです.この場合,コンストラクション関数Function()はeval()よりも手応えがある.

var code = ....;  // A string of JS code to evaluate
var f = new Function(code);   // Wrap it in a function
f();    // And run the function

このような問題は,関数が密封された役割ドメインを作り出し,中の値を知ることができないことである.
次は私が見つけた方法があります.(他にも考えている人がいるに違いありませんが、他の場所に現れたり、説明したりしたことはありません)コードを含む前に、この文を追加します.

return function(s) { return eval(s); };

これで、この関数を呼び出すと、匿名の関数が返されます.返される関数は、ネーミングスペースの役割ドメインで文字列を実行します.
だからあなたは彼を使ってネーミングスペースを探して、そしてあなたの望む値を出力することができます!
コード文字列がSet()という構造関数を定義している場合は、ネーミングスペースでコードを実行して、このようにすることができます.
ネーミングスペースから抽出

var code = readFile("Set.js");  // A string of JS code to evaluate
// Define and invoke a wrapper function with special suffix code.
// The return value is a namespace evaluator function and we treat
// it as a namespace object.
var setns = new Function(code + "return function(s) { return eval(s); };")(); 
var Set = setns("Set");  // Import the Set function from the namespace.
var s = new Set();  // Use the class we just imported

名前空間から抽出したいものが3つあるなら


// Extract an object containing 3 values from the namespace
var sets = setns('{Set:"Set", BitSet:"BitSet", MultiSet:"MultiSet"}');
var bs = new sets.BitSet();


コードをロードし、このようなネーミングスペースを自動的に生成するためのnamespace()関数を定義しました.

/*
 * Load modules of code by enveloping them in a function and executing
 * the function: then they don't pollute the global namespace (unless they
 * assign to undeclared variables, but ES5 strict mode will prevent that.)
 * The wrapper function we create returns an evaluator function that 
 * evals a string inside the namespace. This evaluator function is the
 * return value of namespace() and provides read access to the symbols 
 * defined inside the namespace.
 */
function namespace(url) {
    if (!namespace.cache) namespace.cache = {};  // First call only
    if (!namespace.cache.hasOwnProperty(url)) {  // Only load urls once
        var code = gettext(url);           // Read code from url
        var f = new Function(code +        // Wrap code, add a return value
                             "return function(s) { return eval(s); };");
        namespace.cache[url] = f.call({}); // Invoke wrapper, cache evaluator
    }
    return namespace.cache[url];  // Return cached evaluator for this namespace
}
 
/* Return the text of the specified url, script element or file */
function gettext(url) {
    if (typeof XMLHttpRequest !== "undefined") { // Running in a browser
        if (url.charAt(0) == '#') {              // URL names a script tag
            var tag = document.getElementById(url.substring(1));
            if (!tag || tag.tagName != "SCRIPT")
                throw new Error("Unknown script " + url);
            if (tag.src) return gettext(tag.src);// If it has a src attribute
            else return tag.text;                // Otherwise use script content
        }
        else {                                   // Load file with Ajax
            var req = new XMLHttpRequest();
            req.open("GET", url, false);         // Asynchronous get
            req.send(null);
            return req.responseText;             // Error handling?
        }
    }
    else if (typeof readFile == "function") return readFile(url);  // Rhino
    else if (typeof snarf == "function") return snarf(url); // Spidermonkey
    else if (typeof read == "function") return read(url);   // V8
    else throw new Error("No mechanism to load module text");
}

これらの関数はnamespaceで見つけることができます.jsでは、私は簡単なdemoを書いて、それは何も面白いことをしていません.alertが256をしただけです.
しかし、コードを見ると、4つのコードブロックをロードしてネーミングスペースを生成していることがわかります.
もしあなたがPythonプログラマーであれば、この技術はpython式の「AからBへの接続」タイプのテンプレートシステムを補充するために使用できるかもしれないと思いますが、私はずっとこのようなことを考えています(コードを共有するつもりはありません).
欠点は、もちろんあなたのネーミングスペースで定義されたすべての文字を列挙することはできませんので、pythonのインタフェースを真似することはできません.
翻訳:
http://www.davidflanagan.com/2009/11/functions-as-na.html