• 编写高质量的JavaScript代码


    一、编写高质量的JS代码

    1、团队合作,如何避免js冲突

      1)用匿名函数将脚本包起来,可以有效控制全局变量,避免冲突隐患。

      2)为了不同代码段之间相互通信,需要定义全局变量

      3)当需要的全局变量太多时,为防止全局变量泛滥,定义一个全局对象,公用的变量作为全局对象的属性

      4)为防止相同属性相互覆盖的问题,引入命名空间的概念。GLOBAL对象的属性不要直接挂在GLOBAL对象上,而是挂在此匿名函数的命名空间下。

      5)如果同一个匿名函数中的程序非常复杂,变量名称很多,命名空间还可以进一步扩展,生成二级命名空间。

      6)将生成命名空间的功能定义成一个函数,方便调用。

      7)以上解决了代码冲突问题,但是可维护性并不强,我们需要添加适当的注释,以提高代码的可维护性。

    总结:让JS不产生冲突,需要避免全局变量的泛滥,合理使用命名空间以及为代码添加可维护的注释。

    2、给程序一个统一的入口——window.onload和DOMReady

     1)网页中的javaScript从功能上,应该分为两大部分——框架部分和应用部分,框架部分提供的是对javaScript代码的组织作用,包括定义全局变量,定义命名空间方法等。它和具体应用无关。

    应用部分提供的是页面应用逻辑,不同页面会有不同功能。我们需要将应用部分的代码组织起来,给它们一个统一的入口。function init(){应用部分代码}

     2)javaScript是脚本语言,加载到哪儿执行到哪,如果程序控制某个节点,而该节点当时还没有被载入,程序就会报错。我们可以监听window对象的onload事件,当window触发onload事件后调用脚本

    3)window.load需要当页面完全加载完成时才会触发包括图片、flash等富媒体,DOMReady只判断页面内所有DOM节点是否已经全部生成,至于节点的内容是否加载完成并不关心,所有DOMReady触发

    速度比window.onload更快,更适用于来调用初始化函数。

    4)DOMReady并不是原生javascript支持的事件,它不能像window.onload那样直接调用,一般我们都是结合JS框架来使用它。如jQuery中$(document).ready(init);如YUI中YAHOO.until.Event.onDOMReady(init)

    5)在</body>之前调用入口函数也可以实现DOMReady的效果

    6)在实际工作中,网站的头部和尾部通常会做成单独的文件,用服务器端语言include到网页中,所以我们通常将网页拆分成三个文件:头部文件、尾部文件、主体文件

       头部和尾部调用,如果仅仅为静态HTML的话,只能采用框架。

       如果采用动态语言,则可以用服务器端包含,把头部和尾部文件调用进来。<!--#include virtual="html/head.html"-->这种包含方式是ASP动态语言的。

      ASP的运行需要服务器的支持。不能直接在本地用浏览器浏览,但是可以在本地搭建一个ASP服务器,然后运行。网络上也有ASP本地测试工具,把该文件放到ASP站点的根目录下双击运行就可以浏览ASP网页了

    7)if(init){

      init();

    }

    在调用init函数之前,先判断页面内是否已经定义了init函数,如果定义了才会去执行。增强代码健壮性。

    3、CSS放在页头,JavaScript放在页尾

      将CSS放在页头,在载入HTMl元素之前,先载入它们的样式,这样可以避免HTML出现无样式状态;将JavaScript放在页尾,先将网页呈现给用户,再来加载页面内的脚本,避免JavaScript阻塞网页

      的呈现,减少页面空白的时间。

    4、引入编译的概念——文件压缩

     1)JavaScript压缩工具有Packer和YUI Compressor;

        Packer的网址是:http://dean.edwards.name/packer/  它的使用非常方便

       YUI Compressor的网址是:http://developer.yahoo.com/yui/compressor/(如果不想安装JDK可以通过http://refresh-sf.com/yui/在线使用YUI Compressor)

       YUI Compressor除了可以压缩javascript代码还可以用来压缩CSS代码

      2) JS压缩通常的做法是去掉空格和换行,去掉注释,将复杂变量名替换成简单的变量名。但影响了代码的可读性,对于代码维护非常不利。所以除了压缩后的文件,我们还需要保留压缩前的原始文件,以备维护之需。

        为了维护方便,源文件的文件名和压缩文件的文件名应建立起对应关系,比如源文件叫做head.js,压缩后的文件可以叫做head-min.js,以此来表明它们之间的关系。

        除了压缩,我们还可以对JavaScript进行反压缩,http://jsbeautifier.org/这个工具就是一个在线反压缩工具,它可以把压缩后的JavaScript文件重新格式化。但需要注意的是,它仅仅是从缩进上对JavaScript进行了反压缩,已经去掉的注释和已经改名的变量是无法恢复的。

      3)JavaScript的分层概念和JavaScript库

      分层可以让我们的代码组织条理更清晰,减少冗余,提高代码重用率。和CSS一样,把JavaScript也分成三层。从上往下依次是base层、common层和page层

       (1)base层

        位于三层的最底端,这层有两个职责:一是封装不同浏览器下JavaScript的差异,提供统一的接口,我们可以依靠它来完成跨浏览器兼容的工作。职责二是扩展JavaScript语言底层的接口,让它提供更多更为易用的接口。base层的功能是给common层和page层提供接口

     base层提供接口,解决浏览器兼容问题:

      (1)如:在使用寻找下一个节点时,Firefox会将包括空白、换行等文本信息也当做childnodes中的一员,而IE会忽略它,只将DOM元素当做是childnodes的一员。如此一来,我们编写的程序就无法兼容IE和Firefox了。

      解决办法:用getNextNode函数封装IE和Firefox的差异。代码如下:(document.all是IE支持的属性,Firefox不支持)

          

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <ul>
    <li id="item1">1</li>
    <li id="item2">2</li>
    <li id="item3">3</li>
    </ul>
    <script>
    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){
    nextNode=nextNode.nextSibling;
    }else{
    break;
    }
    }
    }
    }
    return nextNode;
    }
    var nextNode=getNextNode("item1");
    alert(nextNode.id);
    </script>
    </body>
    </html>

      通过getNextNode函数我们轻松实现了跨浏览器兼容,这里的getNextNode函数就是我所说的接口。base层的作用之一就是提供大量类似的接口,用来屏蔽原生Javascript在不同浏览器下的差异。

     (2)IE下透明度是通过滤镜实现的,而在Firefox下透明是通过CSS的opacity属性实现的。封装setOpacity函数。

    <style>
    #text1{
    background:blue;
    height:100px;
    }
    #text2{
    background:green;
    height:100px;
    }
    </style>
    <div id="text1"></div>
    <div id="text2"></div>
    <script>
    function setOpacity(node,level){
    node=typeof node=="string" ? document.getElementById(node) : node;
    alert(node);
    if(document.all){
    node.style.filter='alpha(opacity='+level+')';
    }else{
    node.style.opacity=level/100;
    }
    }

    </script>

     (3)event对象

       不同浏览器中,除了DOM的表现会有所不同,事件的表现也有很大不同。在IE下,event对象是作为window对象的属性作用于全局作用域的,而在Firefox中,event对象作为事件参数存在的。

      event对象的部分属性名在IE和Firefox下也是不同的,比如派生事件的对象在IE下是通过event对象的srcElement属性访问的,而在Firefox下,是通过event对象的target属性访问的

       封装getEventTarget函数

          function getEventTarget(e){

        e=window.event||e;

              return e.srcElement || e.target;

      }

     (4)event对象的冒泡

       当父元素中包含子元素时,为父元素和子元素分别绑定点击事件,当去点击子元素时,结果是子元素的事件先触发,父元素的点击事件随后触发,JavaScript对这种先触发子容器监听事件,后触发父容器事件监听事件的现象称为事件的冒泡。如何解决这个问题:

      我们需要阻止点击按钮时的事件冒泡。阻止事件冒泡在IE下是通过设置event对象的cancelBubble属性为true实现的,而在Firefox下则是通过调用event对象的stopPropagation方法实现的。

      封装阻止事件冒泡的动作:   

    function stopPropation(e){
    e=window.event||e;
    if(documnet.all){
    e.cancelBubble=true;
    }else{
    e.stopPropagation();
    }
    }

    (5)on、attachEvent、addEventListener
    如果我们要让某个DOM节点监听事件,最简单的方法就是使用on XXX 方法,如:
    var btn=document。getElementById('btn');
    btn.onclick=function(){
      alert(1);
    }
    如果我们需要让click事件再次触发另一个监听函数,
     var btn=document。getElementById('btn');
    btn.onclick=function(){
      alert(1);
    }
    btn.onclick=function(){
      alert(2);
    }
    我们希望点击按钮时,能将两个监听函数都触发,先弹出1,接着弹出2.但事实上,后面的btn.onclick会把前面的btn.onclick覆盖掉,点击按钮时,只会弹出2
    on XXX的监听方式没有叠加效果,最后定义的on XXX会将前面的覆盖掉,所以这种写法很危险,特别是在多人合作时,不仅全局变量会让多人合作中产生意外的冲突,on XXX监听也会产生冲突。
    为解决这个问题,可以使用attachEvent和addEvenntListener方法代替on XXX监听事件。其中attachEvent是支持IE的方法,addEventListener是Firefox支持的方法。
    attachEvent和addEvenntListener方法支持监听处理函数的叠加,而不是覆盖
     var btn=document。getElementById('btn');
    if(document.all){
      btn.attachEvent("onclick",function(){
      alert(1);
    });
    }else{
      btn.addEventListener("click",function(){
      alert(1);
    }
    if(document.all){
      btn.attachEvent("onclick",function(){
      alert(2);
    });
    }else{
      btn.addEventListener("click",function(){
      alert(2);
    }
    在IE和Firefox下点击按钮都可以顺利弹出1和2.只是可读性太差,来进行一下封装

    function on(node,eventType,handler){
    node=typeof node=="string"?document.getElementById(node):node;
    if(document.all){
    node.attachEvent('on'+eventType,handler);
    }else{
    node.addEventListener(eventType,handler,false);
    }
    }
    var btn=document.getElementById('btn');
    on('btn','click',function(){
    alert(1);
    });
    on('btn','click',function(){
    alert(2);
    });

    base层的第二个职责是“扩展JavaScript语言底层的接口”。我们可以自定义一些常用方法来弥补原生JavaScript的缺漏。常用方法:
    (1)trim()
    在做表单验证的时候,我们常常需要检查输入框是否为空,一个简单的做法是判断inputNode.value=‘’,但如果输入空格、缩进字符等字符,就可以绕过这个判断了。我们可以定义这么一个函数:
    function trim(ostr){
      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 typeof s===null;
    }
    function isUndefined(s){
    return typeof s==="undefined";
    }
    function isEmpty(s){
    return /^s*$/.test(s);
    }
    function isArray(s){
    return s instanceof Array;
    }

    (2)在写JavaScript代码时,最常用的函数就是document.getElementById(),但它实在是太长了,所以很多人干脆用一个简单的函数来代替它,用的比较多的是get()或者$(),还可以再稍微往前一步,参数除了DOM节点外,
    还可以直接使用DOM节点本身。
    function get(node){
    node=typeof node=="string"?document.getElementById(node):node;
    }
    function $(node){
    node=typeof node=="string"?document.getElementById(node):node;
    }
    alert(get('test1').innerHTML);
    alert($('test2').innerHTML);

    getElementByClassName()以及extend后续补充

       (2)common层

      位于三层的中间,依赖于base层提供的接口。common层提供可供复用的组件,它是典型的mvc模式中的m,和页面内的具体功能没有直接关系。common层的功能是给page层提供组件。

    common层本身依赖base层提供的接口,所以如果要使用common层的组件,必须先加载base层的代码。

    common层主要封装组件:如GLOBAL.Cookie,为用户提供更好用的read、set、del方法。对于用户来说,并无需了解GLOBAL.Cookie的内部实现,不用和原生JavaScript中的Cookie相关的API打交道,只需要知道GLOBAL.Cookie提供了那些接口就可以了。

    base层提供的接口和任何具体的功能无关,非常底层,所以也非常常用。common层提供的组件并不像base层那么通用,它和具体的功能相关,如果页面里不需要相关的功能,就没必要加载。而且一个易用性、重用性、扩展性都非常好的组件,代码量往往偏高,所以common层的JS需要按功能分成一个个单独的文件,例如:common_cookie.js等,按需加载

    common层的组件不仅依赖base层接口,有时也依赖common层的其他组件,在加载时注意导入JS文件的顺序。

      (3)page层

      位于三层的最顶端。这一层和页面里的具体功能需求直接相关,是mvc模式中的c。page层依赖于base层和commom层。page层的功能是完成页面内的功能需求。

  • 相关阅读:
    python random 随机选择操作
    分类预测,交叉验证调超参数
    7种炫酷HTML5 SVG液态水滴融合分解动画特效
    SAP WEBSERVICE Soap中RPC-style和Document-style
    Cocos2d-x 3.0final 终结者系列教程02-开发环境的搭建
    C#创建Excel文件并将数据导出到Excel文件
    某一天,忽然发现自己坚持不下去了。(无关计算机,仅仅是一些自己的困惑和感想)
    HDU4300-Clairewd’s message-KMP
    Java深入
    IOS UITextView光标位置在中间的问题
  • 原文地址:https://www.cnblogs.com/WEI-web/p/6491790.html
Copyright © 2020-2023  润新知