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



一:

团队合作避免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.nextSibling){
				    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 over

			var 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(){
							   //遍历数组,隐藏所有tabcontent
							   for(var j=0;j<tabcontent.length;j++){
							      tabcontent[j].style.display = "none";
								  }
							  //显示被点击的tabMenus 对应的tabcontent
							  tabcontent[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(){
							   //遍历数组,隐藏所有tabcontent
							   for(var j=0;j<tabcontent.length;j++){
							      tabcontent[j].style.display = "none";
								  }
							  //显示被点击的tabMenus 对应的tabcontent
							  tabcontent[_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(){
							   //遍历数组,隐藏所有tabcontent
							   for(var j=0;j<tabcontent.length;j++){
							      tabcontent[j].style.display = "none";
								  }
							  //显示被点击的tabMenus 对应的tabcontent
							  tabcontent[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 adang
	                setTimeout(adang.say,1000);  // I'm somebody
			setInterval(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 adang
	                 btn.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 somebody
			setInterval(adang.say,1000);  // I'm somebody
			setTimeout(function(){ adang.say.apply(btn)},1000);  // I'm BUTTON
	</script>

=============================分割线=====================待续=====================================

顺便吐槽一下--------写着写着内容多了以后,编辑起来就很非常不方便了! 内容一多,“选择”这个功能基本就无法使用了

内容再多点,就形成了无法输入的状态,得从外部复制进来了......

这是不是很大的BUG啊。。。。。。。。。。。。。

搞得界面都不是很友好的说(设置不了哎..)

时间: 2024-10-07 01:20:11

编写高质量 Javascript -- 知识点小记的相关文章

深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点(转)

才华横溢的Stoyan Stefanov,在他写的由O’Reilly初版的新书<JavaScript Patterns>(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会是件很美妙的事情.具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使用单变量声明,在循环中预缓存length(长度),遵循代码阅读,以及更多. 此摘要也包括一些与代码不太相关的习惯,但对整体代码的创建息息相关,包括撰写API文档.执行同行评审以及运行JSLint.这些习惯和最佳做法可以

编写高质量JavaScript代码的68个有效方法

简介: <Effective JavaScript:编写高质量JavaScript代码的68个有效方法>共分为7章,分别涵盖JavaScript的不同主题.第1章主要讲述最基本的主题,如版本.类型转换要点.运算符注意事项和分号局限等.第2章主要讲解变量作用域,介绍此方面的一些基本概念,以及一些最佳实践经验.第3章主要讲解函数的使用,深刻解析函数.方法和类,并教会读者在不同的环境下高效使用函数.第4章主要讲解原型和对象,分析JavaScript的继承机制以及原型和对象使用的最佳实践和原则.第5章

编写高质量javascript代码的基本要点

javascript入门比较快,基础方面也比较简单,但如果想写出高质量的javascript代码也绝非易事,下图是在下整理的编写高质量javascript代码的基本要点,希望能够对各位有所帮助.

《编写高质量JavaScript代码的68个有效方法》

第1章 让自己习惯JavaScript 第1条:了解你使用的JavaScript版本 决定你的应用程序支持JavaScript的哪些版本. 确保你使用的JavaScript的特性对于应用程序将要运行的所有环境都是支持的. 第2条:理解JavaScript的浮点数 JavaScript中的数字都是作为双精度的64位浮点数来储存的:而JavaScript的整数都仅仅是双精度浮点数的一个子集,不是单独的数据类型.而小数和小数相加有时候是不精确的,如果你用作货币计算,最好换算成最小的货币来计算. 第3条

Effective JavaScript: 编写高质量JavaScript代码的68个有效方法(目录)

本书赞誉译者序序前言第 1 章 让自己习惯 JavaScript 1第 1 条: 了解你使用的 JavaScript版本 1第 2 条:理解 JavaScript 的浮点数 6第 3 条:当心隐式的强制转换 8第 4 条:原始类型优于封装对象 13第 5 条: 避免对混合类型使用== 运算符 14第 6 条:了解分号插入的局限 16第 7 条: 视字符串为 16 位的代码单元序列 21第 2 章 变量作用域 25第 8 条:尽量少用全局对象 25第 9 条:始终声明局部变量 27第 10 条:避

0003.深入理解JavaScript系列学习:编写高质量JavaScript代码的基本要点

推荐 汤姆大叔博客园深入理解JavaScript系列 此文来源:http://www.cnblogs.com/TomXu/archive/2011/12/28/2286877.html 书写可维护的代码(Writing Maintainable Code ) 即 代码的可读写维护性 博客园<行者自若的技术笔记> 中参考代码规范与读写可维护性 可作为参考,我也转载了文章到自己的博客园 http://www.cnblogs.com/wolongjv/articles/5937898.html 概括

编写高质量javascript代码(1-10)

第1条:了解你使用的js版本 许多js引擎支持const关键字定义变量,但ECMAScript标准并没有定义任何关于const关键字的语义和行为.此外,在不同的实现之间,const关键字的行为也是不一样的. 在某些情况下,const关键字修饰的变量不能被更新: 1 const PI = 3.14.592653589793; 2 PI = "modified"; 3 PI; //3.14.592653589793 而其他的实现只是简单地将const视为var的代名词: const PI

&lt;深入理解JavaScript&gt;学习笔记(1)_编写高质量JavaScript代码的基本要点

注:本文是拜读了 深入理解JavaScript 之后深有感悟,故做次笔记方便之后查看. JQuery是一个很强大的JavaScript 类库,在我刚刚接触JavaScript的就开始用了. JQuery使用起来非常方便,以至于我这样的JS小白在任何网站上都会毫不犹豫的引入JQuery.....(我想这样做的不止我一个人吧,哈哈) 由于最近新项目中开始使用各种JavaScript 插件(JQueryUI, JQuery.dataTable,uploadify等....),需要进一步封装,以方便使用

[转] 翻译-高质量JavaScript代码书写基本要点 ---张鑫旭

by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1173 原文作者:Stoyan Stefanov原文链接:The Essentials of Writing High Quality JavaScript翻译编辑:张鑫旭 //zxx: 俗不可耐的开场白就免了,直接进入翻译内容(其实是因为本文是在太..太..长了,). 教程相关细节主题:JavaScript最佳实践难度