读书人

怎么访问作为命名空间的函数内部变量

发布时间: 2012-10-27 10:42:26 作者: rapoo

如何访问作为命名空间的函数内部变量
把函数做为命名空间已经是当今javascript编程里非常普遍的了。如果你把你的代码包含在一个函数里,那么你的代码里包含的变量和函数对于包含函数是本地的,或者说是局部的,这样则不会扰乱全局作用域。

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 evaluatevar f = new Function(code);   // Wrap it in a functionf();    // 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 namespacevar 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

读书人网 >Web前端

热点推荐