本文共 2829 字,大约阅读时间需要 9 分钟。
在SeaJS官网上推荐了源码阅读顺序,本文并没有采用这个顺序,而是按个人习惯以调试官方示例的方式进行源码阅读。早期版本作者玉伯使用了几个闭包形式,本文源码版本为2.1.1,它的编码方式个人认为更加脚本化,该版本代码量不到1K。
1. 使用Chrome打开《》中的hello.html文件,按F12打开JavaScript控制台,依次选择Source > sea.js,可以看到SeaJS使用了一个大的闭包:
(function(global, undefined)
{
if(global.seajs){
return;
}
//...略
})(this);
说明:this是Window对象,同时把Window对象赋值给global变量,这样在这个闭包中使用Window的地方均可以用global代替。
2. hello.html文件中使用<script s rc="../sea-modules/seajs/seajs/2.1.1/sea.js"></script>引入sea.js,所以浏览器解析html文件时会加载sea.js代码。加载完sea.js后Window对象结构如图一:
(图一)
3. 从上图中可以看到seajs的初始值的大体轮廓,下面我们看一下seajs.data值的由来:
// 定义seajs.data变量对象
var data = seajs.data = {};
// 定义seajs.data的事件集合
var events = data.events = {};
// 定义已加载模块的集合
var fetchedList = {};
data.fetchedList = fetchedList;
// 设置字符集
data.charset = "utf-8";
// 定义获取依赖模块个数方法
var _cid = 0;
function cid(){
return _cid++;
}
data.cid =cid;
// 把document和location对象赋值给doc、loc
var doc = document;
var loc = location;
// 通过文档location对象获取hello.html文件所在的路径,并把其赋给data.cwd作为当前工作路径
var DIRNAME_RE = /[^?#]*\//
function dirname(path){
return path.match(DIRNAME_RE)[0];
}
var cwd = dirname(loc.href);
data.cwd = cwd;
// 通过文档document对象读取hello.html文件中引入seajs的路径,并把其设置为加载路径
function getScriptAbsoluteSrc(node){
return node.hasAttribute ? node.src : node.getAttribute("src", 4);
}
var scripts = doc.getElementsByTagName("script");
var loaderScript = doc.getElementById("seajsnode") || scripts[scripts.length - 1];
var loaderDir = dirname(getScriptAbsoluteloaderScript ) || cwd);
data.dir = loaderDir;
说明:dirname()函数的逻辑
(1)URL路径的基本知识
常见URL写法如
当在百度中搜索“url”字符串时,浏览器显示的url为http://www.baidu.com/s?wd=url,用?表示后面跟随的是参数;
当在谷歌中搜索“url”字符串时,浏览器显示的url值为http://www.google.com.hk/#fp=11d84258cf3e1c4a&q=url,其中#是指导浏览器动作的,对服务端没有任何用途。关于URL中#号的作用,感兴趣的读者可以参考《http://www.ruanyifeng.com/blog/2011/03/url_hash.html》。
(2)入参path的值为file:///E:/seajs/officialsample/app/hello.html,而DIRNAME_RE正则表达式的含义原来“不是?或#的0个或多个字符 + / ”,由于*在正则表达式中是贪婪的,所以它匹配的值为[file:///E:/seajs/officialsample/app/],然后取集合中的第一个,所以函数返回的值为file:///E:/seajs/officialsample/app/
说明:getScriptAbsoluteSrc()函数的逻辑
function getScriptAbsoluteSrc(node){
return node.hasAttribute ? node.src : node.getAttribute("src", 4);
}
(1)入参node的值为loaderScript,经上面初始化后loaderScript值为<script s rc="../sea-modules/seajs/seajs/2.1.1/sea.js" />
(2)在非IE6、IE7中node具有hasTrribute属性,所以此处为了兼容IE6、IE7这里使用了node.getAttribute("src", 4)方法,获取node对象中的src对应值
// 从加载路径中获取seajs所属路径作为根路径
var BASE_RE = /^(.+?\/)(\?\?)?(seajs\/)+/
data.base = (loaderDir.match(BASE_RE) || ["", loaderDir])[1];
说明:解释BASE_RE正则表达式
(1)它分为三部分^(.+?\/)、(\?\?)?和(seajs\/)+,第一部分匹配以xxx/格式开头的字符串,第二部分匹配零个或多个??,第三部分匹配一个或多个seajs/字符串
(2)match()表示:如果没有找到任何匹配的文本将返回null,否则它将返回一个数组。该数组的第0个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表式匹配的文本
(3)由于loaderDir的值为file:///E:/seajs/officialSmaple/sea-modules/seajs/seajs/2.1.1/,匹配之后的值为["file:///E:/seajs/", "file:///E:/", undefined, "seajs/" ],所以data.base的值为file:///E:/
转载地址:http://gjvax.baihongyu.com/