一月 26th, 2010

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

前端开发, 翻译, by army8735.

原文标题:《Functions as Namespaces, and How to Peek Inside》

原文地址:http://www.davidflanagan.com/2009/11/functions-as-na.html

很精彩的技巧,通过闭包和eval()的使用,达到标题中的功能。

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

以上代码是我们经常用到的技巧:赋值时通过执行一个匿名函数来防止一些代码变量污染全局空间,并且函数内部可以写很复杂的实现而无需担心对外部的影响。

但是有些情况下我们得到的js代码是一串字符串——例如,用xhr读取到的js代码。倘若想要使用它,可以用eval(),还可以用更方便的Function()构造器。

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

//army注:这段代码和下面是完全等同的:
function f() {
	alert(1);
}
f();

所以,通过这种技巧,哪怕是从一段js字符串源代码来赋值,也是可行的:

var code = "return 3;";
var f = new Function(code);
var i = f(); //i是3

但是这里却有一个问题。因为是由Function()构造函数而来的,相当于创造了一个密封的命名空间(所有代码都在一个匿名function内执行),我们无法从外部访问它。倘若里面有一些定义的类或者函数之类的东西,那就难办了。比如这样:

var code = "function Test() {};";
var f = new Function(code);
f();
//这相当于执行了以下方法:
function f() {
	function Test() {
	}
};
f();

内部定义了一个Test类,我们很难访问到它。不过这里有个技巧——这也是本篇要介绍的主角——可以通过闭包+eval()结合使用来绕过这种限制。

var code = "function Test() { alert('a test'); };";
var f = new Function(code + "return function(s) { return eval(s); };")(); //关键!还有后面的括号!
var Test = f("Test");
new Test();

如何?内部的Test类成功从外部创建了。关键就在于第2行,这里有个小小限制,第3行传入的参数需和要使用的内部变量名相等。外部的Test其实相当于密封函数内的Test的一个copy,没想明白的话根据代码倒着走一遍就ok了。

Back Top

回复自“如何访问作为命名空间的函数内部变量”

  1. 哈,你还自己详细演示了代码

  2. 这样还不如直接使用eval。。。

  3. 我说错了,一开始没看仔细,sorry…

  1. 没有任何引用。

发表回复

Back Top