如何访问作为命名空间的函数内部变量

把函数做为命名空间已经是当今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 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的接口

翻译自:[url]http://www.davidflanagan.com/2009/11/functions-as-na.html[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值