// 我们为了让正则表达式工作得更快,因此笔者实现一个方便的 // 正则表达式编译方法,使得它更加简单易用 // 使得你不必再使用复杂、烦琐的compile方法 // 使用举例:var r /\s[a-z]\s/.cmp(); RegExp.reg = /(?:\/)([gmi]*$)/.compile("(?:\\/)([gmi]*$)", ""); RegExp.prototype.cmp = function() { var s = String(this).substr(1), m = RegExp.reg.exec(s); return this.compile(s.substr(0, s.length - m[0].length), m[1] || ""); }; // 正则表达式集中管理和维护, // 最主要的是进行预编译,使得运行更快 // 不过这里只集中那些在function中的,不是程序[js]装载时能编译的正则表达式 Object.jcoreRegs = [ /*00*/ /[^\x00-\xFF]/gm.cmp(), /*01*/ /^[\da-z_\u4E00-\u9FA5]+[\da-z_\.-\u4E00-\u9FA5]*@[\da-z\u4E00- \u9FA5]+[\da-z\u4E00-\u9FA5_-]+(\.[\da-z\u4E00-\u9FA5_-]+)+$/i.cmp(), /*02*/ /^[_a-z][_a-z0-9\.-]*@[_a-z0-9\.-]+(\.[_a-z0-9\.-]+)+$/i.cmp(), /*03*/ /^(\d+)\.(\d+).(\d+).(\d+)$/.cmp(), /*04*/ /^(?:\s*[,;\|]?\s*)(\d+)(?:\s*[-~]\s*)(\d+)(?:\s*)/.cmp(), /*05*/ /^\s*\[?\s*\d+(\s*[,;\|&]\s*\d+)*\]?\s*/.cmp(), /*06*/ /[\s\[\]]/g.cmp(), /*07*/ /[,;\|&]/.cmp(), /*08*/ /^(?:\s*)([><])(?:\s*)(\d+)(?:(?:\s*[;,\|&]\s*)([><])(?:\s*)(\d+))?/.cmp(), /*09*/ /\s/gm.cmp(), /*10*/ /(^['"])|(['"]$)/.cmp(), /*11*/ /(\s*>\s*<\s*)|(^\s*<\s*)|(\s*>\s*$)/gm.cmp(), /*12*/ /\s{2,}/gm.cmp(), /*13*/ /(\s*>.<\s*)|(\s*[,;\|]\s*)/.cmp(), /*14*/ /^[!!]/.cmp(), /*15*/ /\d/g.cmp(), /*16*/ /(^\s*)|(\s*$)/gm.cmp() ]; // 这段代码只在这里出现一次,然后就移进Jcore.js里 // 获取当前浏览器信息 var b = navigator.userAgent.toLowerCase(); // 浏览器 Object.browser = { version: (b.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], safari: /webkit/.test(b), opera: /opera/.test(b), msie: /msie/.test(b) && !/opera/.test(b), mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b) }; // 特殊的Float属性处理 Object.styleFloat = Object.browser.msie ? "styleFloat" : "cssFloat", // 属性转换对照,你可以扩展它来支持更多的特别属性,如果 Object.props = { "for": "htmlFor", "class": "className", "float": Object.styleFloat, cssFloat: Object.styleFloat, styleFloat: Object.styleFloat, Float: Object.styleFloat, innerHTML: "innerHTML", value: "value", readonly: "readOnly", maxlength: "maxLength", tagname:"tagName" }; // 浏览器类型检测 // 操作符号转换 Object.opts = { "=" : "==" , "<>" : "!=" , "gt" : ">" , "lt" : "<" , "eq" : "==" , "~=" : function(szParm, szAtt) { // 匹配属性szAtt,以空格分隔的其中一个等于,或者全等于szParm szParm = szParm.toLowerCase, szAtt = szAtt.toLowerCase; return szParm == szAtt || -1 < szAtt.split(/\s+/).indexOf(szParm); } , "^=" : function(szParm, szAtt) { // 匹配属性szAtt,以szParm开头的节点 return 0 == szAtt.toLowerCase().indexOf(szParm.toLowerCase()); } , "$=" : function(szParm, szAtt) {// 匹配属性szAtt,以szParm结尾的节点 szParm = szParm.toLowerCase, szAtt = szAtt.toLowerCase; return (szAtt.length - szParm.length) == szAtt.lastIndexOf(szParm); } , "*=" : function(szParm, szAtt) { // 匹配属性szAtt,包含szParm的节点 return -1 < szAtt.toLowerCase().indexOf(szParm.toLowerCase()); } , "|=" : function(szParm, szAtt) { // 匹配属性szAtt以szParm + 【_-】连接符号开始的节点 szParm = szParm.toLowerCase, szAtt = szAtt.toLowerCase; return 0 == szAtt.indexOf(szParm + "-") || 0 == szAtt.indexOf (szParm + "_"); } }; // 谓词、伪模式定义 Object.mtps = { // 查找frame和iframe对象 "frame":function(o) { var aRst = []; // 设置不再对frame和iframe对象进行深度迭代 aRst.bNs = true; // 考虑到性能问题,这些方法我们在迭代的时候都取消了深度迭代 // 因为默认我们已经取所有的HTML对象进行迭代了,因此没有必要加深度迭代的加了后, // 反而导致有的对象迭代多次,而push不得不改为add,这时候性能就更受到影响了 // 因为add为了防止将重复的对象加进去,虽然做了最大的优化始终不如不用深度迭代 return o.each(function() { switch(this.nodeName) { case 'FRAME': case 'IFRAME': aRst.push(this); break; } }), aRst; }, // 筛选输入对象 "input":function(o) { var aRst = []; // 考虑到性能问题,这些方法我们在迭代的时候都取消了深度迭代 // 因为默认我们已经取所有的HTML对象进行迭代了,因此没有必要加深度迭代的加了后, // 反而导致有的对象迭代多次,而push不得不改为add,这时候性能就更受到影响了 // 因为add为了防止将重复的对象加进去,虽然做了最大的优化始终不如不用深度迭代 return o.each(function() { switch(this.nodeName) { case 'INPUT': case 'SELECT': case 'TEXTAREA': case 'BUTTON': aRst.push(this); break; } }), aRst; }, // 筛选文本输入对象 "text":function(o) { var aRst = [], rg = /^text$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=text]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选密码输入对象 "password":function(o) { var aRst = [], rg = /^password$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=password]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选radio单选输入对象 "radio":function(o) { var aRst = [], rg = /^radio$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=radio]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选checkbox多选输入对象 "checkbox":function(o) { var aRst = [], rg = /^checkbox$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=checkbox]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选提交按钮输入对象 "submit":function(o) { var aRst = [], rg = /^submit$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=submit]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选图形按钮输入对象 "image":function(o) { var aRst = [], rg = /^image$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=image]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选reset重置按钮输入对象 "reset":function(o) { var aRst = [], rg = /^reset$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.push(this); }); delete rg; return aRst; // 实际上我们可以这样: return XPath.bind({obj:o}, "[type=reset]")() // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选按钮输入对象 "button":function(o) { var aRst = [], rg = /^button^/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.add(this); }); delete rg; return aRst; // 实际上我们可以这样: XPath.bind({obj:o}, "[type=button]")(); // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 筛选不可见输入对象 "hidden":function(o) { var aRst = [], rg = /^hidden$/i.cmp(); o.each(function() { if(rg.exec(this['type']))aRst.add(this); }); delete rg; return aRst; // 实际上我们可以这样: XPath.bind({obj:o}, "[type=hidden]")(); // 但是,往往有时候代码空间却能置换性能的空间,也就是说,多写些代码性能反而会更高 }, // 从匹配的元素集中取第一个元素 "last":function(o) { return o.get(o.size() - 1) || null; }, // 从匹配的元素集中取第一个元素 "first":function(o) { return o.get(0) || null; }, // 从匹配的元素集中取序数为偶数的元素,包含第一个元素 "even":function(o) { var aRst = [], i = 0; o.each(function() { if(0 == i % 2)aRst.add(this); i++; }); return aRst; }, // 从匹配的元素集中取序数为偶数的元素,不包含第一个元素 "odd":function(o) { var aRst = [], i = 1; o.each(function() { if(0 == i % 2)aRst.add(this); i++; }); return aRst; }, // 选择包含有子元素的元素,或者,如果指定为parent(3)则表示选择元素的父节点的 // 父节点的父节点,也就是往上3级的节点 "parent":function(o, n) { var aRst = []; if(n) { o.each(function() { var oTmp = this, i = 0; for(;n > i; i++) { if(!oTmp.parentNode)break; oTmp = oTmp.parentNode; } if(i == n)aRst.add(oTmp); }); } else { o.each(function() { if((this.hasChildNodes && this.hasChildNodes()) || (this.childNodes && this.childNodes.length))aRst.add(this); }); } return aRst; }, // 选择checked属性为真的元素。 "checked":function(o) { var aRst = []; o.each(function() { // !!将表达式结果转换为有效的Boolean对象 if(true == !!this.getAttribute('checked'))aRst.add(this); }); return aRst; }, // 选择enabled属性为真的元素 "enabled":function(o) { var aRst = []; o.each(function() { // !!将表达式结果转换为有效的Boolean对象 if(true != !!this.getAttribute('disabled'))aRst.add(this); }); return aRst; }, // 选择disabled的元素 "disabled":function(o) { var aRst = []; o.each(function() { if(true == !!this.getAttribute('disabled'))aRst.add(this); }); return aRst; }, // 没有子元素(包括text节点)的元素 "empty":function(o) { var aRst = []; o.each(function() { if((this.hasChildNodes && !this.hasChildNodes()) || !this.childNodes)aRst.add(this); }); return aRst; }, // 排除not(s)里指定的s规则的集合 "not":function(o, s) { var a = XPath.bind({obj:o},s)(); var aRst = []; if(0 < a.length) o.each(function() { if(-1 == a.indexOf(this))aRst.add(this); }); else return o; return aRst; }, // 用参数s中的XPath在当前集合中每个元素里执行,然后再返回最后的结果集合 // each node "ecnd":function(o, s) { var a = []; if(0 < o.length) s && o.each(function() { [].push.apply(a, [this].J(s)); }, false); return a; }, // 功能更强大的获取方式,s可以是下面形式中的一种,注意,下面说的位置都是从零开始 // 3-7或4~8,表示获取第三个到第七个,第四个到第八个,他们都包含三和七, // 四和八这个位置的对象,这样的也可以多对组合 // 3,6,8或者[3,6,8],表示你要下标为3、6、8的对象 // >6&<3,表示,获取下标大于6和小于3的对象,中间可以用"&,;|"来分隔 "get":function(o, s) { var aRst = [], i = 0, m = null, r; // 特别需要注意的是,下面的if判断的模式是要注意顺序的, // 认为第二个if中的模式也能匹配第二个 // 处理 3-7或4~8这样的形式 // 这里看上去似乎是不正确的写法,正确的应该是null != (m = /^(?:\s*[,;\|]?\s*)(\d+)(?:\s*[-~]\s*)(\d+)(?:\s*)/.exec(s)) // 不过,我们大可以像下面这样简化它的 // 我们先给模式r变量赋予值,然后用逗号运算符号连接,使得m是最终的if判断的对象 if(r = Object.jcoreRegs[4],m = r.exec(s)) { var bStart = false; if(m[2] > m[1]) { o.each(function() { if(i >= m[1] && i <= m[2])bStart = true,aRst.add(this); // 加了标志是为了减少没必要的迭代 else if(bStart)throw {message:'调处each', jname:"J"}; i++; }); } s = s.replace(r, ''); while(m = r.exec(s)) { bStart = false; if(m[2] > m[1]) { o.each(function() { if(i >= m[1] && i <= m[2])bStart = true,aRst.add(this); // 加了标志是为了减少没必要的迭代 else if(bStart)throw {message:'调处each', jname:"J"}; i++; }); } s = s.replace(r, ''); if(0 == s.length)break; } } // 处理3,6,8或者[3,6,8],表示你要下标为3、6、8的对象 else if(Object.jcoreRegs[5].exec(s)) { s = s.replace(Object.jcoreRegs[6], '').split(Object.jcoreRegs[7]); o.each(function() { if(-1 < s.indexOf(i))aRst.add(this); i++; }); } // 处理这样的形式:>6&<3 else if(r = Object.jcoreRegs[8], m = r.exec(s)) { var szStr = ''; for(i = 1; i < m.length - 1; i += 2) { if(1 < i)szStr += "||"; szStr += "(i" + m[i] + m[i + 1] + ")"; } var oFun = new Function("i", "return " + szStr.replace(Object.jcoreRegs[9], '')); i = 0; o.each(function() { if(oFun(i))aRst.add(this); i++; }); delete oFun; } delete r; delete m; return aRst; }, // 返回序号大于s的 "gt":function(o, s) { return o.slice(parseInt(s)); }, // 返回序号小于s的 "lt":function(o, s) { return o.slice(0, parseInt(s)); }, // 选择所有指定属性含有指定文本的元素。 // 因此s的格式是: ['属性名', '要包含的值'] "attct":function(o, s) { // 这里我们将串行的Array对象转换到Array对象,当然用eval也是可以的 s = s.replace(/[\[\'\"\]\s]/g.cmp(), "").split(","); var aRst = [], rg = new RegExp(s[1], "gi").cmp(); if(s[0] = s[0] || null) o.each(function() { // Object.props[s[0]] || s[0]如果没找到转义的属性名就用原来的名字 if(rg.exec(this.getAttribute(Object.props[s[0]] || s[0]) || null))aRst.add(this); }); return aRst; }, // 选择所有含有指定文本的元素,主要指text和innerText的内容 "contains":function(o, s) { var aRst = [], rg = new RegExp(s, "gmi").cmp(); o.each(function() { // 如果节点是注释对象,则有text,如果是非IE浏览器,则可能有innerText if(rg.exec(this.innerText || this.value || this.text || this.textContent || ''))aRst.add(this); }); delete s; delete rg; return aRst; }, // 返回隐藏的对象 "hide":function(o) { var aRst = []; o.each(function() { var oStyle = this.style || this.currentStyle || {}; var szHd = oStyle.display || oStyle.visibility || ''; if("hidden" == szHd || "none" == szHd)aRst.add(this); }); return aRst; }, // 返回可见的对象 "visible":function(o) { var aRst = []; o.each(function() { var oStyle = this.style || this.currentStyle || {}; var szHd = oStyle.display || oStyle.visibility || ''; if("hidden" != szHd && "none" != szHd)aRst.add(this); }); return aRst; } }; // 正则表达式集合,集中写在这里便于扩展 // 第一个元素是要执行的函数代码,方法的第一个参数a表示当前可迭代的对象, // m是正则表达式执行后的结果 // 函数返回的结果将作为下一次的传入a,因此返回的结果必须是可迭代的对象 // 每个模式力求功能单一,这样便于维护 // 后面则是支持的多种正则表达式对象 // 注意,每个正则表达式会循环使用,因此请注意,每个必须从头开始匹配 // 一旦匹配到了这段匹配到的串就会从源中删除,进入下轮处理,所以每个匹配不能使用全局 // 另外,每个正则表达式会在while里进行处理,每次使用匹配到的位置为1的结果, // 直到没有匹配才停止 // a默认就是当前的HTML Dom, 初始化是document.all Object.RegExps = [ // 包括html前的<!-- ... -->注释和!DOCTYPE在内的匹配 // 匹配模式是:开头[*!!]中任一个 [function(a, m) { // 匹配:/*/ var aRst = []; return a.each(function() { this['getElementsByTagName'] && aRst.add(_A(this.getElementsByTagName(m[1]) || this)) || this.childNodes && aRst.add(_A(this.childNodes)); }), aRst; }, /^(?:\s*\/?\s*)([\*!!])(?:\s*\/?\s*)/.cmp()] // 匹配: // , /descendent-or-self::node()/,等于document.documentElement,包含html在内的节点 , [function(a, m) { return _A(document.getElementsByTagName("*"), true); }, /^(\s*\/\s*){2}/.cmp(), /^\s*\/\s*descendent\s*-\s*or\s*-\s*self\s*:\s*:\s*node\s*\(\s*\)\s*\/\s*/i.cmp()] // 匹配: ":input"这种形式的谓词 , [function(a, m) { // 匹配到的临时结果 var aMyTmp = [], szParm = m[3] || ""; m[1] = Object.mtps[m[1].trim().toLowerCase()]; if(m[1]) { aMyTmp = m[1](a, (szParm || '').replace(Object.jcoreRegs[10], '')); delete m[1]; } return aMyTmp; }, /^(?:\s*:\s*)([\w-]+)(?:\s*\(\s*)('?|"?)(?:\s*)(.*)(?:\s*)\2(?:\s*\)\s*)(?:\s*\/?\s*)/i.cmp(), /^(?:\s*:\s*)([\w-]+)(?:\s*\/?\s*)/i.cmp()] // 匹配select,button或#myDivId,button或<div><span> , [function(a, m) { // 匹配到的临时结果 var aMyTmp = [], aM; aM = m[1].trim().replace(Object.jcoreRegs[11], '').replace(Object.jcoreRegs[12], ' ').split(Object.jcoreRegs[13]); delete m[1]; // 如果传进来的是个数组,则对它进行迭代 if(0 < aM.length) { aM.each(function() { var _this = this, rg = new RegExp("^(" + _this + ")$", "i").cmp(); // 对要获取的同级对象进行获取并合并结果 a.each(function(o, i) { !!rg.exec([ this.nodeName || '', this.getAttribute && (this.getAttribute('id') || this.getAttribute('uniqueID')) || '', this.className || ""].join("|")) && aMyTmp.add(this); // 改变fnGetObjs的当前对象为_this, // Array的add方法兼容了HTML DOM的一些操作,请参加Array章节 aMyTmp.add(fnGetObjs.call(this, _this)); }); }); } return aMyTmp; }, /^(?:\s*\/?\s*#?)((?:\s*<?\s*[\w-]+\s*>?\s*[;,\|]?\s*)+)(?:\s*\/?\s*)/i.cmp()] // 匹配:../,当前集合的父节点对象的集合 , [function(a, m) { var aMyTmp = []; a.each(function() { aMyTmp.add(this.parentNode); }); delete a; return aMyTmp; }, /^(\s*\/?\s*\.\s*\.\s*\/?\s*)/i.cmp()] // 匹配:div.myClassName/ , [function(a, m) { m[1] = !!m[1] && m[1] || m[2] || ""; var aMyTmp = []; // 如果传进来的是个数组,则对它进行迭代 if(0 < m[1].length) { var rg = new RegExp(m[1], "i").cmp(); a.each(function() { if(!!rg.exec((this.nodeName || ",") + "|" + (this.id || this.uniqueID || ',') + "|" + (this.className || ","))) aMyTmp.add(this); // 将执行结果合并到临时数组里 aMyTmp.add(fnGetObjs.call(this, m[1])); }); if(0 < aMyTmp.length)a = aMyTmp; } // 对class属性进行过滤 var szPpt = Object.props["class"] || "className"; m[2] = m[2].toLowerCase(); delete aMyTmp, aMyTmp = []; a.each(function() { // 这里过滤掉了文本节点 // if(3 != this.nodeType) if(this.getAttribute && this.getAttribute(szPpt).toLowerCase() == m[2])aMyTmp.add(this); }); return aMyTmp; }, /^(?:\s*\/?\s*)([\w-]*)(?:\s*\.\s*)([\w-]*)(?:\s*\/?\s*)/i.cmp()] // 匹配:[@class]或者[myvalue],匹配有指定属性但是却没有指定值对象或nodeName,或ID , [function(a, m) { var aMyTmp = [], bNot = false, rg = Object.jcoreRegs[14]; // HTML 对象 nodeName、ID、属性名 m[1] = m[1].trimAll(); // 支持div[4]这样的形式 if(0 == m[1].replace(Object.jcoreRegs[15], "").length) { // 匹配到的临时结果 if(0 <= m[1] && m[1] <= a.length) return [a[m[1]]]; return []; } if(rg.exec(m[1])) bNot = true, m[1] = m[1].replace(rg, ""); a.each(function() { // 将执行结果合并到临时数组里 aMyTmp.add(fnGetObjs.apply({obj:this}, [m[1]])); }); // 如果不是选择属性模式就返回了 if(0 < aMyTmp.length)return aMyTmp; // 再做初始化 delete aMyTmp, aMyTmp = []; // 对象属性名,如果转义存在则转义,否则直接使用原来的名字 var szPpt = Object.props[m[1]] || m[1]; a.each(function() { // 不包含给定属性或者需要包含 // 这里过滤掉了文本节点 if(3 != this.nodeType) if((!bNot && this.getAttribute(szPpt)) || (bNot && !this.getAttribute(szPpt)))aMyTmp.push(this); });// 这里本来必须启用深度迭代,不过由于我们在外边已经准备好要迭代的元素, // 为了防止深度递归调用而影响性能,我们取消了所有的深度迭代 // 释放内存是很好的习惯 delete szPpt; return aMyTmp; }, /^(?:\s*\/?\s*\[\s*@?\s*)(!?\s*[\w-]+)(?:\s*\]\s*\/?\s*)/i.cmp()] // 匹配:[div @styleFloat='left']或者[@styleFloat!='left'] , [function(a, m) { var aMyTmp = []; if(4 > m.length)return a; // HTML 对象 nodeName m[1] = m[1].trimAll(); // HTML 对象属性名 m[2] = m[2].trimAll(); // 如果没取到属性名,表示属性名已经落到对象名上 m[2] || (m[2] = m[1], m[1] = ""); // HTML 对象属性操作符号 m[3] = m[3].trimAll(); // 操作符号需要转义,如果没有定义相应的转义就直接使用 m[3] = Object.opts[m[3]] || m[3]; // HTML 对象属性操作的值 m[4] = m[4].toLowerCase(); // 如果只是[@styleFloat!='left']/span这样的形式,m[1]是可能为空的 // 如果传进来的是个数组,则对他进行迭代 if(0 < m[1].length) { a.each(function() { // 将执行结果合并到临时数组里 aMyTmp.add(fnGetObjs.apply({obj:this}, [m[1]])); }); if(0 < aMyTmp.length)a = aMyTmp; // aMyTmp2 = null;也可以,不过我们测试发现delete性能比直接赋予null更优秀 } // "? (expression): (expression);"三目运算符号中的(expression) // 可以随便给个字符, // 表示给一个为定义的变量,等于用 undefined,或者用''一对引号也可以 // 对属性进行过滤,m[2] 属性名称, m[3] 是运算符号, m[4] 是属性值 delete aMyTmp, aMyTmp = []; // 对象属性名,如果转义存在则转义,否则直接使用原来的名字 var szPpt = Object.props[m[2]] || m[2]; // 定义操作函数对象,注意new Function这样的形式的上下文是不同它的容器的, // 这个匿名函数不一样 // 因为这里需要组装代码,所以我们必须用new Function这样的动态形式 var szCode = "return (s||'').toLowerCase()" + m[3] + "'" + m[4] + "'"; try { var oFunc = Function == m[3].constructor && m[3] || new Function("szParm", "s", szCode); a.each(function() { // 这里过滤掉了文本节点 if(3 != this.nodeType) if(oFunc(m[4], this.getAttribute(szPpt)))aMyTmp.push(this); }); }catch(e){} // 释放内存是很好的习惯 delete oFunc; delete szPpt; return aMyTmp; }, /^(?:\s*\/?\s*\[\s*)([\w-]*)(?:\s*@?\s*)([\w-]*)(?:\s*)([=!<>\s\^~$\*\|]+)(?:\s*['"]?\s*)([\w-\(\)]+)(?:\s*["']?\s*\]\s*\/?\s*)/i.cmp()] ]; // 功能描述:将当前对象toString或者传入的第一个参数toString或转换为 // html中能正确显示的文本,也就是把html代码转换为能在页面上正确显示的文本 // 返回信息:元素的个数 // 使用指南:[].size(); // 等于0 // 应用范围:各种Web客户端 Object.prototype.sanitizeHTML = function(s) { var d = document.createElement('div'); d.appendChild(document.createTextNode(s || this.toString())); return d.innerHTML; }; // 功能描述:将当前对象传递到callback回调函数里执行 // 使得XPath选择器更加方便地对临时结果进行处理,然后再进行其他 // XPath选择器处理,这样就使得每个XPath选择不必都从所有对象中进行检索 // 从而提高了性能,它区别于every的是,它将整个对象作为一个参数传递给回调函数 // 而不像every,它接收的是对象的单个元素。every是第4章的内容 // 返回信息:返回当前的对象 // 使用指南:[12,33.98, 887].getAll(function(){}).each(function(){}); // 应用范围:各种Web客户端和服务器端 Object.prototype.getAll = function(callback) { callback && callback.apply(this, [this]); return this; }; // Xpath选择器的设计 var XPath = Object.prototype.XPath = function(s1) { // if(0 == arguments.length)return new XPath(this.toString()); // 正则表达式 var s = (s1 || this.toString() || "").trim(), a, m, x, i, oT; if(0 == s.length)return []; // 结果数组a, 模式匹配结果m, this.obj是为了支持指定开始选择的接点对象 var atmp = []; // 如果节点太多,建议使用更详细的xpath选择器,而不应该依赖智能的选择, // 因为越智能也就越消耗性能 // 因此这里当节点大于300就把根作为默认开始节点 a = this.length && this || _A( this.obj || (atmp = (this.win || window).document.getElementsByTagName("*"), 300 < atmp.length ? (this.win || window).document.documentElement : atmp) );
// 定义一个标签,表示我们将在多重循环的最里面停止我们最外面的循环 var nF = Object.RegExps.length % 8, n1, oN = nF, j, oMyRg, oFn; // 注意,JavaScript也支持Labeled 语句,不过在firefox中不支持, // 因此真正的示例中我们没有这样做 ExitAllDo: do { i = 0; n1 = nF, j = 0; // 执行 取8余数的零头的循环 do { // 初始化 if(j >= Object.RegExps.length)j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; oFn = oMyRg[0]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new oFn(a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) }while(j++,0 < n1--);
n1 = (Object.RegExps.length - oN) / 8; // 八分法开始 do { // 初始化: 1 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if(null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 2 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 3 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 4 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 5 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 6 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 7 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; // 初始化: 8 if(j >= Object.RegExps.length) j = 0; x = 1; // 如果当前是多个组合:text,select这样的形式,则认为需要合并结果 // 每个匹配允许有多个正则表达式的匹配 do { oMyRg = Object.RegExps[j]; if( null != (m = oMyRg[x].exec(s))) { i++; // 模式方法执行返回的结果 oT = new Object.RegExps[j][0](a, m); // 下一轮的结果从它开始选择 switch(oT.constructor) { case Array: a = oT; break; default: (a = []).push(oT); } s = s.replace(oMyRg[x], ""); delete oT; break; } if(0 == s.length || 0 == a.length)break ExitAllDo; }while(++x < oMyRg.length) j++; }while(0 < n1--); // 如果匹配完成,或者整个模式都没有任何匹配就退出 // 防止死循环是设计中应该常常考虑的 if(0 == s.length || 0 == i || 0 == a.length)break; }while(s.length > 0) return a; }; 测试的iframe文件“ifrm.jsp”的内容: <body> <button class="myTestGood" name="myTest" id="myTest">测试绑定事件1</button> <br><br> <button name="myTest1" id="myTest1" >绑定前面按钮的onmouseover1</button><br> <button name="myTest1" class="myTestGood">卸载onmouseover前面按钮的onmouseover1</button><br> </body> |