日期:2014-05-16  浏览次数:20299 次

Javascript中实现JS文件的导入+命名前缀

?Javascript不比Java,没有import关键字(据说Javascript2.0将加入Import和命名空间)。在网上查了很多别 人写的Import函数的代码,通常都是直接在HTML里插入script元素来实现。这种方式无法实现同步导入,即import函数调用的下面无法马上 使用导入JS里面的变量。

下面的代码将使用AJAX方式来实现Import功能,可以实现同步导入。调用方式很简单,在JS代码开始处调用$import()函数就可以了。

另外本代码还集成了CSS的导入,虽然很简单但也很有用。因为如果你编写了一个JS文件来实现某种控件,你肯定不希望使用你的JS文件的人还要在他自己的代码里引入你的CSS文件。所以你可以使用本代码里的$import函数在你的JS文件中引用你的CSS文件。

最后,本代码还提供了一个很振奋的功能,即为你导入的JS文件中的全局变量加上命名前缀。我们在很多高级语言中都可以做到这一点,如引用JAVA的JSP标签库,<%@ taglib uri="http://java.sun.com/jsp/jstl/core " prefix="c"%>,这个库里面的内容可以用前缀C与其他标签库区分开来。本代码也提供了类似的功能,如:$import("../lib/head.js","h")。之后就可以用h.XXX来引用head.js里定义的函数和变量了。

代码如下:

/**
 * 这个JS文件提供了命名空间、JS文件导入功能。 注:import本身是个关键字,不能用来做变量函数名
 * 通过本代码可以导入Javascript文件,可以使用绝对URL和相对URL作为路径 $import("../lib/head.js");
 * $import("head.js"); 可以导入CSS文件 $import("head.css");
 * 导入Javascript文件时,可以为导入文件里所定义的全局变量增加前缀,如: $import("prototype.js","p"); var
 * mydiv = p.$("myDiv");
 * 但只有用var定义的全局变量和全局函数将增加前缀,而没有用var定义的变量将被视为必须要为全局的变量,不增加前缀
 * 
 * @author 由月
 */
var Import = {};

Import.importedJSFiles = [];
Import.importingJSFiles = [];
Import.importedCSSFiles = [];

Import.$import = function(url, prefix) {
	// 检查参数合法
	if (url == null || url == "")
		return;
	// 获取导入文件的完整URL
	var fullUrl = Import.getFullPathFromUrl(url);
	// 先将此URL放入正在导入的列表中
	Import.addImportingFile(fullUrl);
	// 判断导入的是JS文件还是CSS文件
	if(Import.getFileType(fullUrl) == ".js"){
		Import.importJS(fullUrl, prefix);
	} else {
		Import.importCSS(fullUrl);
	}
	// 将URL从正在导入列表中移除,并加入已导入列表
	Import.addImportedFile(fullUrl);
};
Import.importCSS = function(url) {
	// 检查此文件是否已经被导入过
	if (Import.isImported(url))
		return;
	var head = document.getElementsByTagName("head")[0];
	// IE6 cannot support appendchild for head when BASE tag is present.
	// So we have to use document.write as instead.
	// We need better solution for this IE bug.
	// var link = head.appendChild(document.createElement("link"));
	var link = document.createElement("link");
	link.href = url;
	link.type = "text/css";
	link.rel = "stylesheet";
	if (document.readyState == "complete") {
		// if this method is called after the page loaded, for example,
		// in a script with defer tag, then use appendChild,
		// otherwise the document will be cleared when invoking
		// document.write.
		head.appendChild(link);
	} else {
		document.write(link.outerHTML);
	}

};
Import.importJS = function(url, prefix) {
	// 检查此文件是否已经被导入过
	if (Import.isImported(url))
		return;
	// 通过AJAX获取文件内容
	// alert(url);
	var script = Import.getScriptContent(url);
	// alert(script);
	// 加上命名空间并执行脚本
	Import.execute(script, prefix);
};
Import.execute = function(script, prefix) {
	if (prefix != null &amp;&amp; prefix != "") {
		var variables = Import.analysScript(script); // 分析出脚本中所有的全局变量
		if (variables.length &gt; 0) {
			var pre = eval(prefix + " = {};"); // 根据prefix生成对象
			for ( var i = 0; i &lt; variables.length; i++) {
				var variable = variables[i];
				// alert(variable);
				pre[variable] = null;
			}
			var extendScript = "; var pre="
					+ prefix
					+ ";for(var attr in pre){try{pre[attr]=eval(attr);}catch(e){}}";
			var wholeScript = "(function(){" + script + extendScript + "})();";
			window.execScript(wholeScript);
		}
	} else {
		window.execScript(script);
	}
};
Import.analysScript = function(script) {
	// 检查参数
	if (script == null || script == "")
		return null;

	var globalVariables = null;
	// 定义词法状态机
	var wordStateMachine = {
		currentState : "init", // 状态机的当前状态
		wordCache : [], // 保存用来构造单词的缓存
		stateObj : {}, // 保存状态间变量
		getStateObj : function(state) {
			if (state &amp;&amp; state != "") {
				if (this.stateObj[state] == null)
					this.stateObj[state] = {};
				return this.stateObj[state];
			}
			return null;
		},
		process : function(script) {
			var self = this;
			var index = 0;
			var outputWords = [];
			while (index &lt; script.length) {
				var c = script.charAt(index);
				var result = "self"