把函数做为命名空间已经是当今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的接口
翻译自:
http://www.davidflanagan.com/2009/11/functions-as-na.html
分享到:
相关推荐
若内部变量标示,如: 当使用“from M import”时,不会将以一个下划线开头的对象引入 。 2、 __xx 双下划线的表示的是私有类型的变量。只能允许这个类本身进行访问了,连子类也不可以用于命名一个类属性(类变量)...
(1)加在局部变量的前面使之成为静态局部变量,作用域还是在函数内部,可是生存周期延长了。 (2)加在全局变量的前面限定该变量作用域为文件作用域,就是说即使其他文件使用了extern扩展作用域也不行。这在C语言的...
命名空间是一个声明性区域,为其内部的标识符(类型、函数和变量等的名称)提供一个范围。命名空间用于将代码组织到逻辑组中,还可用于避免名称冲突,尤其是在基本代码包括多个库时。命名空间范围内的所有标识符彼此...
又由于复合语句肯定是包含在函数内部(要么在主函数main()内,要么在自定义函数内),所以C语言中全局变量的定义“在所有函数之外”的说法同样适合C++。具有全局作用域的变量的作用域从定义位置起,到整个转换单元...
作用域作用域作用域的查找顺序新作用域的引入目录Contents01作用域作用域作用域就是一个 Python 程序可以直接访问命名空间的正文区域。Python 中,变量的访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了...
文章目录python基础-函数详解一、什么是函数二、函数的作用三、定义函数四、函数的作用域和命名空间1.作用域(scope):变量生效的区域2.命名空间(namespace)五、调用函数1.函数递归:2.高阶函数:五、函数中的参数...
LZInit 这个函数用于初始化内部缓冲区 LZOpenFile 该函数能执行大量不同的文件处理,而且兼容于压缩文件 LZRead 将数据从文件读入内存缓冲区 LZSeek 设置一个文件中进行读写的当前位置 MapViewOfFile 将一个文件...
闭包就是由其他函数动态生成并返回的函数,通俗地讲,在一个函数的内部,还有一个“内层”的函数,这个“内层”的函数是被返回的,它可以访问其创建者的局部命名空间中的变量。 下面是一个非常简单的例子: # ...
10.2.3 指针变量作为函数参数 137 10.2.4 指针变量几个问题的进一步说明 140 810.3 数组指针和指向数组的指针变量 141 10.3.1 指向数组元素的指针 142 10.3.2 通过指针引用数组元素 143 10.3.3 数组名作函数参数 146...
10.2.3 指针变量作为函数参数 137 10.2.4 指针变量几个问题的进一步说明 140 810.3 数组指针和指向数组的指针变量 141 10.3.1 指向数组元素的指针 142 10.3.2 通过指针引用数组元素 143 10.3.3 数组名作函数参数 146...
起因将代码组织到类中的一个重要原因是让代码更加“模块化”,可以在很多不同的场景中实现代码的重用。但类不是唯一的模块化代码的方式。...实际上,可以将这个函数作用域用做模块的命名空间(模块函数) 一旦将模块
11.2.1 创建命名管道 300 11.2.2 管道监听 302 11.2.3 使用异步I/O进行读写 303 11.2.4 关闭管道实例 307 11.2.5 客户端 307 11.3 剪贴板 310 11.3.1 获取、设置剪贴板数据 310 11.3.2 监视剪贴板 ...
第4章 命名空间和文件 4.1 命名空间 4.1.1 使用声明和指令 4.1.2 多重接口 4.1.3 命名空间别名 4.1.4 无名命名空间 4.1.5 名称查找 4.2 包含文件 4.2.1 包含标准库文件 4.2.2 用户自定义头...
11.2.1 创建命名管道 300 11.2.2 管道监听 302 11.2.3 使用异步I/O进行读写 303 11.2.4 关闭管道实例 307 11.2.5 客户端 307 11.3 剪贴板 310 11.3.1 获取、设置剪贴板数据 310 11.3.2 监视剪贴板 ...
简而言之,就是能够读取其他函数内部变量的函数。 由于JS变量作用域的特性,外部不能访问内部变量,内部可以外部变量。 二、使用场景 1. 实现私有成员。 2. 保护命名空间,避免污染全局变量。 3. 缓存变量。 先看一...
具有内部链接性的: · 所有的声明 · 命名空间(包括全局命名空间)中的静态⾃由函数、静态友元函数、静态变量的定义、const常量定义 · enum定义 · inline函数定义(包括⾃由函数和⾮⾃由函数) · 类(class、struct...
命名空间5. 递归函数 1. 函数的返回值 返回值就是函数执行以后返回的结果 通过return来指定函数的返回值 return后面可以跟任意对象,返回值甚至可以是一个函数 2. 文档字符串 help()是Python中内置函数,通过help()...
元素的 localName 和命名空间决定了它的内部槽集。 new Foo的返回值以Foo.prototype作为原型。 其 (localName, namespace) 对与概念 (localName, namespace) → 构造函数注册表中的条目匹配的元素,除非作为其在...