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 && prefix != "") {
- var variables = Import.analysScript(script); // 分析出脚本中所有的全局变量
- if (variables.length > 0) {
- var pre = eval(prefix + " = {};"); // 根据prefix生成对象
- for ( var i = 0; i < 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 && 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 < script.length) {
- var c = script.charAt(index);
- var result = "self";
- var word = self.wordCache.join("");
- while (result == "self") { // 继续在当前字符上调用handler
- result = self.handlers[self.currentState](c);
- }
- if (result == "complete") { // 完成了一个单词的分析
- // alert(word);
- var output = grammarStateMachine.process(word);
- if (output != null) {
- // alert("output:" + output);
- outputWords[outputWords.length] = output;
- }
- } else if (result == "next") { // 读取下一个字符
- self.wordCache[self.wordCache.length] = c;
- index++;
- }
- }
- return outputWords;
- },
- handlers : {
- "init" : function(char) {
- wordStateMachine.wordCache = [];
- if ("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- .indexOf(char) >= 0) {
- // if(char == "$")alert(char);
- wordStateMachine.currentState = "identify_start";
- } else if ("{}()".indexOf(char) >= 0) {
- wordStateMachine.currentState = "block_start";
- return "self";
- /*
- * } else if ("/"'".indexOf(char) >= 0) { //
- * 暂时取消字符串分析,因为不好处理正则表达式中的'和" wordStateMachine.currentState =
- * "quote_start";
- * wordStateMachine.getStateObj("quote_start").quote = char;
- * return "next";
- */
- } else if (char == "/") {
- wordStateMachine.currentState = "comment";
- return "next";
- }
- return "next";
- },
- "identify_start" : function(char) { // 进入标识符分析
- var result = "self";
- if ("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_"
- .indexOf(char) >= 0) {
- result = "next";
- } else if ("".indexOf(char) >= 0) {
- } else {
- wordStateMachine.currentState = "identify_finish";
- result = "self";
- }
- return result;
- },
- "identify_finish" : function(char) { // 标识符分析完成
- var result = "complete";
- wordStateMachine.currentState = "init";
- return result;
- },
- "block_start" : function(char) { // 分析括号和代码块
- wordStateMachine.currentState = "block_finish";
- return "next";
- },
- "block_finish" : function(char) {
- wordStateMachine.currentState = "init";
- return "complete";
- },
- "quote_start" : function(char) { // 分析引号
- // alert(char + "," + wordStateMachine.wordCache.join(""));
- var finish = false;
- if (char == wordStateMachine.getStateObj("quote_start").quote) {
- for ( var i = wordStateMachine.wordCache.length - 1; i >= 0; i = i + 2) {
- var a = wordStateMachine.wordCache[i];
- var b = wordStateMachine.wordCache[i - 1];
- if (a != "//") {
- finish = true;
- break;
- } else if (b != "//") {
- finish = false;
- break;
- }
- }
- if (finish) {
- wordStateMachine.currentState = "quote_finish";
- return "self";
- }
- }
- return "next";
- },
- "quote_finish" : function(char) {
- alert(char + "," + wordStateMachine.wordCache.join(""));
- wordStateMachine.currentState = "init";
- return "next";
- },
- "comment" : function(char) { // 分析注释
- if (char == "/") {
- wordStateMachine.currentState = "comment_start";
- wordStateMachine.getStateObj("comment").comment = "line";
- } else if (char == "*") {
- wordStateMachine.currentState = "comment_start";
- wordStateMachine.getStateObj("comment").comment = "block";
- } else {
- wordStateMachine.currentState = "regex";
- }
- return "self";
- },
- "comment_start" : function(char) {
- // alert(char+","+wordStateMachine.wordCache.join(""));
- if (wordStateMachine.getStateObj("comment").comment == "line"
- && char == "/n") {
- wordStateMachine.currentState = "comment_finish";
- } else if (wordStateMachine.getStateObj("comment").comment == "block"
- && char == "/"
- && wordStateMachine.wordCache[wordStateMachine.wordCache.length - 1] != "//") {
- wordStateMachine.currentState = "comment_finish";
- }
- return "next";
- },
- "comment_finish" : function(char) {
- wordStateMachine.currentState = "init";
- return "next";
- },
- "regex" : function(char) {
- // TODO: 需要实现表达式分析才能分析出正则表达式
- wordStateMachine.currentState = "init";
- return "next";
- }
- }
- };
- // 定义语义状态机
- var grammarStateMachine = {
- currentState : "init",
- output : null,
- stateObj : {},
- getStateObj : function(state) {
- if (state && state != "") {
- if (this.stateObj[state] == null)
- this.stateObj[state] = {};
- return this.stateObj[state];
- }
- return null;
- },
- process : function(word) {
- var self = this;
- var result = "self";
- var ret = null;
- while (result == "self") {
- result = self.handlers[self.currentState](word);
- }
- if (result == "next") {
- } else if (result == "complete") {
- ret = self.output;
- self.output = null;
- }
- return ret;
- },
- handlers : {
- "init" : function(word) {
- // alert("init:"+word);
- if (word == "var") {
- grammarStateMachine.currentState = "variable_define";
- } else if (word == "function") {
- grammarStateMachine.currentState = "function_define";
- } else if (word == "{") {
- grammarStateMachine.currentState = "block";
- grammarStateMachine.getStateObj("block").blockLevel = 0;
- return "self";
- }
- return "next";
- },
- "block" : function(word) {
- var stateObj = grammarStateMachine.getStateObj("block");
- if (word == "{") {
- stateObj.blockLevel++;
- } else if (word == "}") {
- stateObj.blockLevel--;
- if (stateObj.blockLevel == 0) {
- grammarStateMachine.currentState = "init";
- } else if (stateObj.blockLevel < 0) {
- throw new Error("block unmatch");
- }
- }
- return "next";
- },
- "variable_define" : function(word) {
- grammarStateMachine.output = word;
- grammarStateMachine.currentState = "variable_finish";
- return "self";
- },
- "variable_finish" : function(word) {
- grammarStateMachine.currentState = "init";
- return "complete";
- },
- "function_define" : function(word) {
- if (word == "(") {
- grammarStateMachine.currentState = "function_arg_block";
- return "self";
- } else {
- grammarStateMachine.output = word;
- grammarStateMachine.currentState = "function_arg_block";
- }
- return "next";
- },
- "function_arg_block" : function(word) {
- if (word == "(") {
- } else if (word == ")") {
- grammarStateMachine.currentState = "function_search_body";
- }
- return "next";
- },
- "function_search_body" : function(word) {
- if (word == "{") {
- grammarStateMachine.currentState = "function_start";
- grammarStateMachine.getStateObj("function_start").blockLevel = 0;
- return "self";
- }
- return "next";
- },
- "function_start" : function(word) {
- var stateObj = grammarStateMachine
- .getStateObj("function_start");
- if (word == "{") {
- stateObj.blockLevel++;
- } else if (word == "}") {
- stateObj.blockLevel--;
- if (stateObj.blockLevel == 0) {
- grammarStateMachine.currentState = "function_finish";
- return "self";
- }
- }
- return "next";
- },
- "function_finish" : function(word) {
- // alert("function_finish:"+word)
- grammarStateMachine.currentState = "init";
- return "complete";
- }
- }
- };
- // 进入自动状态机
- globalVariables = wordStateMachine.process(script);
- return globalVariables;
- };
- Import.getScriptContent = function(url) {
- var req = new ActiveXObject("Microsoft.XmlHttp");
- var res;
- req.open("GET", url, false);
- req.send();
- if (req.status != 404) {
- if (req.readystate == 4) {
- res = req.responseText;
- }
- }
- return res;
- };
- Import.getFileType = function(url){
- url = url.split("?")[0];
- type = url.substring(url.length - 3);
- if(type.indexOf(".")==0){
- return type;
- }else{
- return "";
- }
- }
- /**
- * 记录下导入的文件
- */
- Import.addImportingFile = function(url) {
- if (!Import.isImported(url)) {
- if(Import.getFileType(url) == ".js")
- Import.importingJSFiles.push(url);
- else
- Import.importingCSSFiles.push(url);
- }
- };
- Import.addImportedFile = function(url) {
- if (!Import.isImported(url)) {
- if(Import.getFileType(url) == ".js"){
- if(Import.importingJSFiles[Import.importingJSFiles.length - 1] == url){
- Import.importingJSFiles.pop();
- Import.importedJSFiles.push(url);
- }
- }else{
- Import.importedCSSFiles.push(url);
- }
- }
- };
- /**
- * 检查文件是否已经被导入过了
- */
- Import.isImported = function(url) {
- if(Import.getFileType(url) == ".js"){
- for ( var i = 0; i < Import.importedJSFiles.length; i++) {
- if (Import.importedJSFiles[i] == url) {
- return true;
- }
- }
- } else {
- for ( var i = 0; i < Import.importedCSSFiles.length; i++) {
- if (Import.importedCSSFiles[i] == url) {
- return true;
- }
- }
- }
- return false;
- };
- /**
- * 获取导入文件的完整URL,包括HTTP头
- */
- Import.getFullPathFromUrl = function(url) {
- var path = null;
- if (url.substr(0, 7).toLowerCase() == "http://") {
- // url为完整的URL地址
- path = url;
- } else if (url.substr(0, 1) == "/") {
- // url以/开头,为以站点根目录开始的路径
- path = "http://" + document.location.host + url;
- } else {
- var parentPage = document.location.href;
- var parentPath = parentPage.split("?")[0];
- parentPath = parentPath.substring(0, parentPath.lastIndexOf("/") + 1);
- var currentScriptPath = Import.getCurrentScriptPath();
- currentScriptPath = currentScriptPath.split("?")[0];
- if (currentScriptPath.toLowerCase().indexOf("http://") == 0) {
- // 当前脚本路径是以http开头
- path = currentScriptPath + url;
- } else {
- // 否则当前脚本路径为相对路径
- // 查看是否有BASE标签
- var base = document.getElementsByTagName("base")[0];
- if (base) {
- var baseUrl = base.href;
- path = baseUrl + currentScriptPath + url;
- } else {
- path = parentPath + currentScriptPath + url;
- }
- }
- path = Import.toAbsolutePath(path);
- }
- return path;
- };
- Import.toAbsolutePath = function(url) { // 转换为绝对URL
- var http = "http://";
- if (url.toLowerCase().indexOf("http://") == 0) {
- url = url.substring(7, url.length);
- }
- var path = url.split("?")[0];
- var queryString = (url.split("?").length > 1) ? "?" + url.split("?")[1] : "";
- dt = path.split("/");
- var newdt = [];
- for ( var i = 0; i < dt.length; i++) {
- var u = dt[i];
- if (u == "..") {
- newdt.pop();
- } else {
- newdt.push(u);
- }
- }
- return http + newdt.join("/") + queryString;
- };
- /**
- * 获取当前运行的脚本文件的路径,路径不包括自身的文件名
- *
- * @return
- */
- Import.getCurrentScriptPath = function() {
- var js = Import.importingJSFiles;
- if (js && js.length > 0) {
- js = js[js.length - 1];
- js = js.split("?")[0];
- js = js.substring(0, js.lastIndexOf("/") + 1);
- } else {
- js = document.scripts;
- var src = js[js.length - 1].src;
- src = src.split("?")[0];
- js = src.substring(0, src.lastIndexOf("/") + 1);
- }
- return js;
- };
- /**
- * ImportFile类
- *
- * @param path
- * @return
- */
- Import.ImportFile = function(path) {
- this.path = path;
- this.fullPath = null;
- this.type = null;
- };
- (function() {
- if (typeof $import == "undefined") {
- $import = Import.$import;
- }
- })();