JavaScript 框架设计(二)
2016-07-23 14:46
531 查看
JavaScript 高级框架设计 (二)
上一篇,JavaScript高级框架设计(一)我们 实现了对tag标签的选择
下来我们实现对id的选择,即id选择器.
我们将上一篇的get命名为getTag(),然后再编写一个getId(),和getClass()
然后在总的get方法中调用,这样做的好处就是模块化,便于维护.
我所有的代码都会托管到github上.
01.js
好了,现在分别实现了三个get方法,但是怎么根据选择器表达式来调用者三个方法呢?
下面引出一个关键正则:
这段正则目的就是匹配id,类和标签选择器,并且通过exec可以拿到匹配的内容.
那么,
m[1] 就表示id选择器,m[2]就表示类选择器,m[3]表示标签选择器,m[4]表示通用选择器
下面的代码就顺理成章了.
01.js
如果没有匹配到,就直接返回result,如果有匹配到,那么就一定是选择器中的一种,通过分组进行判断.
在对每个分组的判断可以优化,
现在这样就已经可以完成对单独选择器的匹配了.
我们来进行测试一遍.
01.html
01.js
下面是结果,是不是欧了?
单独的选择器似乎已经完成,但是一个问题出现了? 有考虑过兼容性吗?
document.getElementsByClassName() ie8以下是不兼容的!
下面引入两个问题:
怎么判断兼容性?
怎么解决不兼容?
然后查看getElementsByClassName() 方法.
经过不断在原型链中搜索,
我们发现其嵌套很深,每次调用都在原型链中搜索.
当我们这样的代码在IE8 以下运行这样的代码时,
它会一直向上寻找,直到Object对象,效率很低.
如果按照上面的代码,那么每调用一次就要就行一次能力检测,效率肯定太低了.
怎么办呢?
方法就是只做一次能力检测,并把它记录下来.
其中,jQuery中就是这么做的,它拥有一个专门的功能检测模块,$.support,里面的属性包含存在兼容问题的方法或属性,并用布尔值来记录.
所以在我们这里,在全局作用域中(最终都要用成沙箱或者闭包)提供一个support对象,里面提供所有的以方法名相同的属性,值均为布尔值,在浏览器加载js的开始的时候,就进行能力判断,凡是涉及到能力检测的时候就直接检测support即可.
所以我们在代码开头加入
那么以后再需要能力检测的时候,可以这么写:
似乎已经可以了.
但是,有一种攻击叫做注入漏洞攻击,我在文件开头嵌入这样的代码(chrome是允许内嵌js代码的!!!):
那么上面的检测还有用吗?
看看jQuery怎么做的,不仅要判断它是否存在,还要判断其能力是否符合要求.
看下面的代码
然后我们在chrome控制台输入
在ie8里,
可以看到,这样很有用.
现在查看jQuery源代码
看它的方法,实在是太简洁了,jQuery留给我们的,就是敬仰!!
现在检查已经完了,怎么解决不兼容问题呢?
原理很简单,通过通用选择器查找到所有的元素,然后看它有木有这个类名,如果有就push.
05.js
这个细节非常重要!!
好了,我们已经添加了自己的getClassName() 方法,现在来测试一遍.
05.html
chrome下效果:
ie8下效果:
关于getElementsByClassName()的兼容问题就讨论到这里,在下一篇,JavaScript高级框架设计(三),我会开始介绍push的兼容问题和 组合选择器.
最后特别感谢恩师蒋坤老师(jk)对我的知识学习和人生引导的极大帮助,非常感谢他.
上一篇,JavaScript高级框架设计(一)我们 实现了对tag标签的选择
下来我们实现对id的选择,即id选择器.
我们将上一篇的get命名为getTag(),然后再编写一个getId(),和getClass()
然后在总的get方法中调用,这样做的好处就是模块化,便于维护.
我所有的代码都会托管到github上.
01.js
var getId = function (id, result) { result = result || []; // 由于获取的Id是一个元素,所以这里使用call. result.push.call(result,document.getElementById(id)); return result; } var getClass = function (className, result) { result = result || []; result.push.apply(result, document.getElementsByClassName(className)); return result; }
好了,现在分别实现了三个get方法,但是怎么根据选择器表达式来调用者三个方法呢?
下面引出一个关键正则:
/^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/
这段正则目的就是匹配id,类和标签选择器,并且通过exec可以拿到匹配的内容.
那么,
var m = expr.exec(selector);
m[1] 就表示id选择器,m[2]就表示类选择器,m[3]表示标签选择器,m[4]表示通用选择器
下面的代码就顺理成章了.
01.js
var get = function (selector, result) { result = result || []; var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/, m = rquickExpr.exec(selector); if (!m) { return result; } if (m[1]) { result = getId(selector); } else if (m[2]) { result = getClass(selector); } else if (m[3]) { result = getTag(selector); } else if (m[4]) { result = getAll(selector); } return result; };
如果没有匹配到,就直接返回result,如果有匹配到,那么就一定是选择器中的一种,通过分组进行判断.
在对每个分组的判断可以优化,
if (m[1]) { result = getId(m[1], result); } else if (m[2]) { result = getClass(m[2], result); } else { result = getTag(m[3] || '*', result) }
现在这样就已经可以完成对单独选择器的匹配了.
我们来进行测试一遍.
01.html
<body> <div>1</div> <div id="k">2</div> <div class="pawn">3</div> <p></p> <p></p> </body> <script src="01.js"></script>
01.js
onload = function(){ each(get("p"),function(){ this.style.backgroundColor = "green"; }) each(get("#k"),function(){ this.style.backgroundColor = "red"; }); each(get(".pawn"),function () { this.style.backgroundColor = "pink"; }) }
下面是结果,是不是欧了?
单独的选择器似乎已经完成,但是一个问题出现了? 有考虑过兼容性吗?
document.getElementsByClassName() ie8以下是不兼容的!
下面引入两个问题:
怎么判断兼容性?
怎么解决不兼容?
怎么判断兼容性?
我们通过chrome watch写上document然后查看getElementsByClassName() 方法.
经过不断在原型链中搜索,
我们发现其嵌套很深,每次调用都在原型链中搜索.
当我们这样的代码在IE8 以下运行这样的代码时,
if(docuemnt.getElementsByClassName(className)){ // }
它会一直向上寻找,直到Object对象,效率很低.
如果按照上面的代码,那么每调用一次就要就行一次能力检测,效率肯定太低了.
怎么办呢?
方法就是只做一次能力检测,并把它记录下来.
其中,jQuery中就是这么做的,它拥有一个专门的功能检测模块,$.support,里面的属性包含存在兼容问题的方法或属性,并用布尔值来记录.
所以在我们这里,在全局作用域中(最终都要用成沙箱或者闭包)提供一个support对象,里面提供所有的以方法名相同的属性,值均为布尔值,在浏览器加载js的开始的时候,就进行能力判断,凡是涉及到能力检测的时候就直接检测support即可.
所以我们在代码开头加入
var support = {}; support.getElementsByClassName = !!document.getElementsByClassName;
那么以后再需要能力检测的时候,可以这么写:
if(support.getElementsByClassName){ //... }
似乎已经可以了.
但是,有一种攻击叫做注入漏洞攻击,我在文件开头嵌入这样的代码(chrome是允许内嵌js代码的!!!):
document.getElementsByClassName = 'pawn';
那么上面的检测还有用吗?
看看jQuery怎么做的,不仅要判断它是否存在,还要判断其能力是否符合要求.
看下面的代码
var support = {}; support.getElementsByClassName = function () { if (!document.getElementsByClassName) { return false; } var div = document.createElement('div'), pWithClass = document.createElement('p'); pWithClass.className = 'pawn-pawn-pawn'; div.appendChild(pWithClass); var res = div.getElementsByClassName('pawn-pawn-pawn'); return res[0] === pWithClass; } ();
然后我们在chrome控制台输入
support.getElementsByClassName
在ie8里,
可以看到,这样很有用.
现在查看jQuery源代码
看它的方法,实在是太简洁了,jQuery留给我们的,就是敬仰!!
现在检查已经完了,怎么解决不兼容问题呢?
解决兼容
怎么解决呢? 首先进行能力检测,如果有,就直接调用,如果没有,实现了一个自己的myGetClassName()方法.
原理很简单,通过通用选择器查找到所有的元素,然后看它有木有这个类名,如果有就push.
05.js
var getClass = function (className, result) { result = result || []; // 首先判断我们的docoument.getElementsByClassName() 有没有这个功能 var res; if (support.getElementsByClassName) { res = document.getElementsByClassName(className); } else { // 自己实现getElementByClassName // 思路 : 首先获得所有元素,然后再在所有元素中获得带有这个类的元素 res = myGetByClassName(className.document); } result.push.apply(result,res); return result; }
var myGetByClassName = function (className, context) { var elements = context.getElementsByTagName("*"), res = []; // 循环判断是否符合要求 each(elements, function () { // 这个细节非常重要 !!!!! if ((" " + this.className + " ").indexOf(" " + className + " ") != -1) { res.push(this); } }) return res; }
这个细节非常重要!!
if ((" " + this.className + " ").indexOf(" " + className + " ") != -1) { res.push(this); }
好了,我们已经添加了自己的getClassName() 方法,现在来测试一遍.
05.html
<body> <div class="dv1">1</div> <div class="dv1">2</div> <div>3</div> <p clss='p1'>4</p> <p clss='p1'>5</p> <p>6</p> <script src="05.js"></script> </body> <script> onload = function () { each(get('dv1'), function () { this.style.backgroundColor = "red"; }); each(get('p1'), function () { this.style.backgroundColor = "green"; }); }; </script>
chrome下效果:
ie8下效果:
关于getElementsByClassName()的兼容问题就讨论到这里,在下一篇,JavaScript高级框架设计(三),我会开始介绍push的兼容问题和 组合选择器.
最后特别感谢恩师蒋坤老师(jk)对我的知识学习和人生引导的极大帮助,非常感谢他.
相关文章推荐
- 优化加载和执行提高javascript性能
- Javascript错误提示--SyntaxError: Illegal return statement
- JS获取长度方法总结
- JS alert() 弹出框乱码的问题
- JavaScript实现拖拽预览,AJAX小文件上传
- Javascript讲解系列之一 Prototype原型链详解
- js获取当前系统时间后台转化为long型
- javascript中&&和||的区别
- js中的面向对象程序设计(2)-创建对象
- js实现简易月历
- ExtJS初体验
- Javascript前端验证码的实现
- JSP基础知识及工程创建
- js中this的用法
- JSP技术(一)
- js中数组的用法
- js注意事项03
- js注意事项02
- 未能加载文件或程序集"Newtonsoft.Json, Version=4.5.0.0
- js注意事项01