您的位置:首页 > Web前端 > JavaScript

编写高质量 Javascript -- 知识点小记

2014-11-01 18:58 155 查看
一:    团队合作避免JS冲突脚本中的变量随时存在冲突的风险,1.   解决办法---用匿名函数将脚本包起来,让变量的作用域控制在匿名函数之内如:
<script type="text/javascript">
(function(){
var a=123,b="12121";
})();
</script>
.....
<script type="text/javascript">
(function(){
var a=123,b="asdasa";
})();
</script>
此番改善之后,匿名function里面的变量作用域不再是window,而是局限在函数内。2.  有时各个函数之间变量又要进行通讯,故又要改善(利用全局作用域)如:
 <script type="text/javascript"> var str; </script><script type="text/javascript">(function(){var a=123,str = b = "12121";})();</script>.....<script type="text/javascript">(function(){var a=123,b=str;})();</script>
3.  但如此一来,工程变大,全局变量未免过多难以管理,(利用hash对象作为全局变量)如:
<script type="text/javascript"> var GLOBAL={}; </script><script type="text/javascript">(function(){var a=123,b = "12121";GLOBAL.str = a;GLOBAL.str2 = b;})();</script>.....<script type="text/javascript">(function(){var a=GLOBAL.str;var b = GLOBAL.str2;})();</script>
4.   不过就算如此,如果工程变大,不同工程师完成不同的函数,变量难免也会冲突, 故又继续改善(GLOBAL 属性不是直接挂在GLOBAL属性对象上,而是挂在此命名函数的命名空间下) 如:<script type="text/javascript"> var GLOBAL={}; </script><script type="text/javascript">(function(){var a=123,b = "12121";GLOBAL.A = {};GLOBAL.A.str = a;GLOBAL.A.str2 = b;})();</script>.....<script type="text/javascript">(function(){var a=GLOBAL.A.str;var b = GLOBAL.A.str2;})();</script>如此种种,函数内属性越复杂,又可以进一步扩展GLOBAL挂载方式.....如 GLOBAL.A={};GLOBAL.A.CAT={};GLOBAL.A.DOG={};GLOBAL.A.DOG.name="aa";GLOBAL.A.CAT.name="bb";5.  进一步,又可以给此命名空间定义方式封装成函数,方便以后调用:如:
<script type="text/javascript">var GLOBAL={};GLOBAL.namespace = function(str){var arr=str.split("."), o = GLOBAL;for(i=(arr[0]="GLOBAL") ? 1 : 0 ; i<arr.length; i++){o[arr[i]] = o[arr[i]] || {};o = o[arr[i]];}}
</script><script type="text/javascript">(function(){var a=123,b = "12121";GLOBAL.namespace("A.CAT");GLOBAL.namespace("A.DOG");GLOBLA.A.CAT.name="aa";GLOBLA.A.DOG.name="bb";})();</script>
二:   方便JS程序执行:     1. 给程序一个统一的入口===== window.onload 或DOMReady  (先把所有函数定义部分放入 init函数中,最后再加载 init()即可使用   如:在DOM节点加载进来之前就调用会出错      
<script type="text/javascript">alert(document.getElementById("test").innerHTML);</script><div id="test">hello ! </div>
改善方式:   调换位置,在DOM节点加载进来之后再调用即可    
<div id="test">hello ! </div><script type="text/javascript">alert(document.getElementById("test").innerHTML);</script>
或者,使用window.onload事件,window对象会在网页内元素全部加载完毕之后才触发onload时间   
<script type="text/javascript">window.onload= function(){alert(document.getElementById("test").innerHTML);}</script><div id="test">hello ! </div>
但此种方式,仍有不足。  window.onload要等到网页元素全部加载才进行  而DOMReady则只要页面内所有DOM节点皆全部生成即可进行。  DOMReady 方式原生JS并不支持,要使用第三方类库(JS框架)如jQuery的方式:    $(document).ready(init);    // init() 是一个函数... $(function(){ ...});  /// 等等等等..  当然了,我们也可以用原生JS模拟DOMReady ,事实上很简单,就是:  
<script type="text/javascript">function init(){alert(document.getElementById("test").innerHTML);}</script><div id="test">hello ! </div><script type="text/javascript">init();</script></body>
如此一来 body标签加载完成之前才调用函数,这种方式也不错!   2.   CSS 文件与 JS 文件的位置   因为JS是阻塞型的,所以一般” CSS放在页头,Javascript放在页尾“   (这样一来,网页先呈现给用户,再慢慢加载页面里面的脚本,减少页面空白的时间)      三.  Javascript 分层概念    一般来说,我们要把Javascript分层三层: base层 --> common层 --> page 层 1. page层  page 层提供统一的接口,可以在这里实现封装不同浏览器下Javascript的差异,依靠它来完成跨浏览器兼容的工作!  还可以扩展Javascript语言底层提供的接口,以便提供出更多有用的接口(主要是为common page 层提供) 各种问题类举:   <1> 在IE中,它只视DOM节点为childNodes中的一员,但在FireFox中,它会将包括空白.换行等文本信息在内的信息也当做childNodes的一员。   未解决此问题,可用 document.all 方式处理,它是IE支持的属性,FireFox不支持   代码如:
                        <ul><li id="item1"></li><li id="item2"></li><li id="item3"></li></ul><script type="text/javascript">var item1 = document.getElementById("item1");var nextNode = item1.nextSibling;if(document.all){while(true){if(nextNode.nodeType == 1){break;}else{if(nextNode.nextSibling4000){nextNode = nextNode.nextSibling;}else{  break;  }}}}alert(nextNode.id);//////////////////////////////////////////////////var item2 = document.getElementById("item2");var nextNode = item2.nextSibling;if(!document.all){while(true){if(nextNode2.nodeType == 1){break;}else{if(nextNode2.nextSibling){nextNode2 = nextNode2.nextSibling;}else{  break;  }}}}alert(nextNode2.id);</script>
哦对,好像有点冗余,那就把这个功能封装成函数吧! 如:
                        <ul><li id="item1"></li><li id="item2"></li><li id="item3"></li></ul><script type="text/javascript">function getNextNode(node){node = typeof node=="string" ? document.getElementById("node") : node;var nextNode = node.nextSibling;if(!nextNode)return NULL;if(!document.all){while(true){if(nextNode.nodeType == 1){break;}else{if(nextNode.nextSibling){nextNode = nextNode.nextSibling;}else{  break;  }}}}return nextNode;}       //funciton overvar nextNode = getNextNode("item1");var nextNode2 = getNextNode("item1");alert(nextNode.id);alert(nextNode2.id);</script>
<2> 透明度的问题:     IE下透明度是通过滤镜实现的,但在FireFox下透明度是通过CSS 的opacity属性实现的   我们把它封装起来   代码如:
         <style type="text/css">#test1 { background:blue; height: 100px;}#test1 { background:blue; height: 100px;}</style><div id="test1"></div><div id="test2"></div><script type="text/javascript">function setOpacity(node,level){         // level 为滤镜程度node = typeof node=="string" ? document.getElementById("node") : node;if(document.all){node.style.filter = 'alpha(opacitu= ' + level + ')';}else{node.style.opacity = level / 100;}}setOpacity("test1",20);   //test1.style.filter = 'alpha(opacitu=20)';setOpacity("test2",80);   //test2.style.opacity = 0.8;</script>
<3> event 对象的问题:    IE下 event对象是作为window的属性作用于全局作用域的,但在FireFox中 event对象是作为事件的参数存在的    所以,为了兼容性,一般考虑用一个变量指向event对象,继而通过这个变量访问event对象    不理解? 代码如下:
<script type="text/javascript">var btn = document.getElementById("btn");btn.onclick = function(e){e  = window.event || e;// ..........接下来你就可以用e了, 比如 e.target 等</script>
另一方面,派生事件的对象在IE下是通过event对象的srcElement属性访问的                              在FireFox下是通过event对象的target属性访问的    如代码: 
<script type="text/javascript">
    var btn = document.getElementById("btn");btn.onclick = function(e){e  = window.event || e;var el = e.srcElement || e.target;alert(el.tagName);</script>
<4> 冒泡问题的处理   首先理解概念---> 对于事件流,浏览器中的事件模型分为两种:捕获型和冒泡型事件   事件的冒泡: Javascript对这种先触发子容器监听事件,后触发父容器监听事件的现象。   事件的捕获: 即相反于冒泡(先父后子)      比如代码中 <div id="wrapper">                         <input type="button" value="click me" id="btn" />                        </div>   我们为id=wrapper绑定事件1,为id=btn绑定事件2,   如此一来,我们的结果却是: 无论点哪里,触发的都是事件1 (因为事件2触发得很快就会迅速转变为事件1)      为了解决,要阻止(对子容器)事件的冒泡机制:IE下通过设置event对象的cancelBubble 为true 实现                                                  FireFox 通过调用event对象的stopPropagation方法实现        封装成函数即是:
                              <script type="text/javascript">function stopPropagation(e){e = window.event || e;if(document.all){e.cancelBubble = true;}else{e.stopPropagation();}}/////////////////////////调用wrapper.onclick = function(){..............}btn.onlcick = function(e){................stopPropagation(e);}</script>
<5>事件监听的处理:           可以简单地使用 onXXX 的方式,              如 btn.onclick = function(){ .......};           但onXXX方法没有叠加作用,后面定义的onXXX会把前面的覆盖掉,为解决此类问题:               IE下引入 attachEvent方法,FireFox 下引入addEventListener方法。      IE下引入 detachEvent方法,FireFox 下引入removeEventListener方法。      如:oSpan.detachEvent("onclick",fnClick);          oSpan.removeEventListener("click",fnClick);      好,我们就把这个功能封装一下:               代码如: 
            <script type="text/javascript">function on(node,eventType,handeler){node = typeof node=="string" ? document.getElementById("node") : node;if(document.all){node.attachEvent("on"+ eventType,handeler);}else{node.addEventListener(eventType,handeler,false);   // 其中第三个参数:true--捕获型,false--冒泡型}}var btn = document.getElementById("btn");on(btn,"click",funciton(){alert(1);});on(btn,"click",funciton(){alert(2);});</script>
<6> 其他小功能:     函数封装实现:    <script type="text/javascript">function trim(ostr){ //trim() 去空格return ostr.replace(/^\s+|\s+$/g,"");}function isNumber(s){return !isNaN(s);}function isString(s){return typeof s === "string";}function isBoolean(s){return typeof s === "boolean";}function isFunction(s){return typeof s === "function";}function isNull(s){return s === null;}function isUndefined(s){return typeof s === "undefined";}function isEmpty(s){return /^\s*$/.test(s);}function isArray(s){return s instanceof Array;}function get(node){ // get() 代替ducument.getElementById() ...alert(get("test1").innerHTML);node = typeof node=="string" ? document.getElementById("node") : node;return node;}function $(node){ // $() 代替ducument.getElementById() ...alert($("test1").innerHTML);node = typeof node=="string" ? document.getElementById("node") : node;return node;}// 原生JS没有getElementByClassName, 那就给它实现一个呗...// getElementByClassName函数接收3个参数,第一个参数为class名(必选),第二个为父容器,缺省值为body节点,第三个参数为DOM节点的标签名。// 函数 实现如下function getElementByClassName(str,root,tag){if(root){root = typeof root=="string" ? document.getElementById("root") : root;}else{root = document.body;}tag = tag || "*";var els = root.getElementByTagName(tag), arr=[];for(var i=0,n=els.length; i<n ; i++){for(var j=0,k=els[i].className.split(" "), l=k.length; j<l; j++){if(k[k] == str){arr.push(els[i]);break;}}}return arr;}//然后我们就可以直接调用啦..var aEls = getElementByClassName("a");var bEls = getElementByClassName("b");// .............</script>2.  common 层:       common层本身依赖于base层提供的接口,common层提供的应该是相对更大的组件,供Javascript调用   3.  page 层         就是具体的页面特设定啦...  四: 编程的其他一些实用技巧:       1.在遍历数组时对DOM监听事件,索引值将始终等于遍历结束后的值。     如某个监听代码:
                          <script type="text/javascript">//遍历数组,让tabMenus 监听click事件  (Tab 组件监听选项卡)for(var i=0;i<tabMenus.length;i++){tabMenus[i].onclick = function(){//遍历数组,隐藏所有tabcontentfor(var j=0;j<tabcontent.length;j++){tabcontent[j].style.display = "none";}//显示被点击的tabMenus 对应的tabcontenttabcontent[i].style.display = "block";}}</script>
              这样做之后,所有content将会隐藏且 有报错--->  tabcontent[i] is undefined !   要怎么改正呢? ----------------------------->        
                         <script type="text/javascript">//方法一: 利用闭包for(var i=0;i<tabMenus.length;i++){(function(_i){tabMenus[_i].onclick = function(){//遍历数组,隐藏所有tabcontentfor(var j=0;j<tabcontent.length;j++){tabcontent[j].style.display = "none";}//显示被点击的tabMenus 对应的tabcontenttabcontent[_i].style.display = "block";}})(i);  // 闭包...}//方法二: 给DOM节点添加 _index属性<script type="text/javascript">for(var i=0;i<tabMenus.length;i++){tabMenus[i]._index = i;tabMenus[i].onclick = function(){//遍历数组,隐藏所有tabcontentfor(var j=0;j<tabcontent.length;j++){tabcontent[j].style.display = "none";}//显示被点击的tabMenus 对应的tabcontenttabcontent[this._index].style.display = "block";}}</script>
2.  另一方面,我们还需要注意控制好 关键字this 的指向问题:       <1> Javascript伪协议和内联事件对this的指向不同     如  
                                    <script type="text/javascript">// 弹出 “A"<a href="#" onclick="alert(this.tagName)";>click me</a>// 弹出 "undefined"<a href="Javascript:alert(this.tagName)">click me</a>//弹出 "true"<a href="Javascript:alert(this==window)">click me</a></script>
<2> setTimeout 和 setInterval 也会改变this指向       他们都是直接调用函数里的this 指向window   如  <script type="text/javascript">var name="somebody";var adang = {name : "adang";say : funciton(){alert("I'm" + this.name);}};adang.say(); // I'm adangsetTimeout(adang.say,1000); // I'm somebodysetInterval(adang.say,1000); // I'm somebody// 解决办法使用匿名函数 --->setTimeout(function(){ adang.say()},1000); // I'm adang</script><3> DomNode.on XXX  方式也会改变this 指向        它将直接调用函数里面的this 指向DomNode   比如:
           <script type="text/javascript">var name="somebody";var btn = document.getElementById("btn");var adang = {name : "adang";say : funciton(){alert("I'm" + this.name);}};adang.say();     // I'm adangbtn.onclick = adang.say;   // I'm BUTTON// 解决办法使用匿名函数 --->btn.onclick = funciton(){ adang.say()} ;  // I'm adang</script>
<4>  对此,另外我们还可以用 call 和 apply 函数来改变处理函数的this指向        比如: <script type="text/javascript">var name="somebody";var btn = document.getElementById("btn");var adang = {name : "adang";say : funciton(){alert("I'm" + this.name);}};adang.say.call(btn); // I'm BOTTON ---- 把this指向改成了按钮adang.say.apply(btn); // I'm BOTTON ---- 把this指向改成了按钮setTimeout(adang.say,1000); // I'm somebodysetInterval(adang.say,1000); // I'm somebodysetTimeout(function(){ adang.say.apply(btn)},1000); // I'm BUTTON</script>=============================分割线=====================待续=====================================顺便吐槽一下--------写着写着内容多了以后,编辑起来就很非常不方便了! 内容一多,“选择”这个功能基本就无法使用了内容再多点,就形成了无法输入的状态,得从外部复制进来了......这是不是很大的BUG啊。。。。。。。。。。。。。搞得界面都不是很友好的说(设置不了哎..)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息