• javascript书写规范


    程序是给人读的,只是偶尔上计算机执行以下

    读<编写可维护的javascript>有感,
    可维护意味着

    1. 容易看懂
    2. 容易修改
    3. 出现错误,容易查找;

    编程风格

    1 基本格式化

    1. 缩进层级 : 用tab制符表进行缩进
    2. 命名 : 驼峰命名法
      • 变量 : 变量名用名词前缀
      • 函数 : 函数名用动词前缀,
        • 比如get,has
      • 常量 : 常量用大写字母加下划线;
      • 构造函数 : 大驼峰命名法;
    3. 行尾分号 : 每一个行尾的分号都不要省略
    4. 直接量
      • 字符串 : 外层用双引号"",内层用单引号'',多行字符串用加号+;
      • undefined : 尽量不用
    5. 对象
      • null : 对象的占位符
      1. 一个变量将要被赋值为对象时,初始化为null
      2. 一个函数返回值是对象时,不符合条件,就返回null(更健壮)
      3. 一个函数的参数是对象时,可以用null(可选)
      4. 每一个属性,方法后面的逗号也不要省略。
    6. 换行: 每一行代码太长了就在运算符后面换行,下一行加两个缩进;
    7. 空行: 在判断语句,注释,方法,逻辑代码块前面加空行;

    2 注释

    1. 单行注释

    独占一行的注释,在注释之前有空行,缩进与下面的代码相同,
    跟在代码后面的注释,再跟代码之间有一个缩进,整体不能太长,
    2. 多行注释

    用于注释多行内容

    • 注释的作用是添加有价值的信息,让代码变得清晰;
    1. 注释声明
      • // TODO: 代码还未完成,应有下一步要做的事情
      • // HACKL: 此代码走了捷径,或应该有更好的解决方法
      • // XXX: 代码有问题,尽快修复
      • // REVIEW: 此代码的任何改动都需要评审

    3 语句和表达式

    1. 任何时候不要省略花括号
    2. 在判断语句中,左花括号之前,右花括号之后各加一个空格;
    if (10 >= 4) {
    
    }
    
    1. for in循环在使用对象的属性名之前,加判断,是否属于该函数
      • for in循环会便利对象的属性以及原型的属性
        var obj = {name: "lifei"},
            k;
        for (k in obj) {
            obj.hasOwnProperty(k){
                console.log(k);
            }
        }
    
    • 如果要查找原型链,就补充注释,提示遍历原型链;
    1. switch语句
        switch (condition) {
            case 'first':
                console.log('first');
                break;
            case 'second':
                console.log('second');
                break;
            default:    //default中没有逻辑
    
    
        }
    

    4 变量,函数和运算符

    1. 变量

    局部变量的声明,初始化尽量放在函数的第一行,每一个声明独占一行.没有初始值的变量放在后面
    2. 函数

    • 声明函数在调用函数之前,
    • 调用函数时,函数名与左括号之间没有空格 getUser('lifei')
    • 在自调用函数中,用小括号把整个自调用函数包起来
        (function(name) {
            console.log(name);
        }('lifei'))
    
    1. 尽量少用eval();
    2. 两个值相比较时,尽量不要用或!=,会涉及强制类型转换,而是使用=,!==;
      • 一个对象和一个简单数据类型用==比较时,会先调用对象的valueOf()f方法,
        转换成字符串,如果没有valueOf(),则调用toString();再进行比较
      • 除非像判断值是否是null或undefined可以用,!=,其他的情况一律使用=,!==;

    编程实践

    5 UI层的松耦合

    1. html文件用来定义页面的数据和语义,结构
    2. css文件用来给页面添加样式,创建视觉效果
    3. js文件用来给页面添加行为
    • 页面的结构就放在html文件中,逻辑行为,数据交互就放在js中,不要混着来;

    松耦合

    一个大系统的每个组件的内容都有限制,就做到了松耦合;

    比如angular中的service.js文件,和js文件;service.js文件是请求数据用的
    如果每一个service.js返回的数据格式都相同(在service.js对返回数据做格式化);
    那么在js文件中就可以吧数据直接拿来用,如果数据格式出现错误,就去service.js文件;
    在controller.js文件中不考虑数据格式的问题;
    这就是松耦合

    将css从js中抽离

    当需要通过js来该不安元素的样式的时候,最好是操作css的className;

    element.className += "reveal"
    

    将js从html中抽离

    不要在html文件中处理业务逻辑,包括点击事件;

    • angular除外,因为angular主打的就是没有DOM操作,即使如此也要尽量不在html文件中操作
      业务逻辑;

    将html从js中抽离;

    不要把大段的html字符串,放在js里,然后直接追加到html中;
    如果有需要:

    1. 从服务器加载;
    2. 使用模板
      模板应写在html文件中,如下:
    <script type="text/x-my-template" id="list-item>
       <ul>
            <li>{{a}}</li>
            <li>{{b}}</li>
            <li>{{c}}</li>
       </ul>
    </script>
    

    在js中:

        var myList = document.getElementById('my-item');        //获取要添加模板的目标元素
        var listItem = document.getElementById('list-item');    //获取模板元素
        var templateText = listItem.text;       //获取模板中的内容
        myList.innerHTML = templateText;        // 把模板中的内容加到目标中
    
    • 在一般项目中,还一个数据传输的问题,一般是用 %s 来表示变量,然后在添加数据时,用
      result.replace(/^s*$/, 替换的数据) ,来吧数据传入模板中的.但是在angular中有{{}},
      没有这个问题
    1. 在复杂的就用模板插件;

    6避免使用全局变量

    使用全局变量容易造成变量名污染;

    1. 在任何作用域,都不要直接使用上级作用域里的变量,如果有需要就以参数的形式穿进来;
    2. 如果在全局作用域和自作用域中,有同名变量,并且需要在自作用域中操纵全局变量;那么
      • 把全局变量当参数穿进来,并改个名字
          (function(_a){
              console.log(_a) ;   //_下划线表示临时的
          })(a)
      
      • 用window.a来访问;
    3. 现在的框架都是使用同样的变量规则:

    一个闭包结构,把一个单一的全局对象挂载到window上(window.Jquery,window.$);
    下分不同的功能模块: $().css; $().html等;
    每个功能模块根据自己的需求拥有自己的属性,方法;
    每个功能模块根据同样一套规则,来命名自己的属性,方法,

    7事件处理

    将事件处理程序和业务逻辑分开

    var myApp = {
        click: function(event) {    //点击事件处理程序
            event.preventDefault();     //阻止浏览器默认事件
            enent.stopPropagation();    //阻止事件冒泡
    
            //业务逻辑,传入的参数是业务逻辑直接使用的参数,而不是event;
            this.show(event.clientX, event.clientY);
        },
        show: function(x, y){   //业务逻辑
            var popup = document.getElementById("pupop");
            pupop.style.left = x + 'px';
            pupop.style.right = y + 'px';
            popup.className = "reveal";
        }
    };
    
    

    事件处理程序:比如阻止事件冒泡,逻辑函数调用放在事件函数里
    业务逻辑放在逻辑处理函数里,分工明确;

    1. 上述传参数的方式是在业务逻辑,十分确定参数的情况下;比如只用到x,y;
      这样写的好处是,逻辑清晰,事件处理程序中明确表示我要处理的是x,y;
      业务逻辑复用性强,在其他地方同样可以调用该函数
      比如 myApp.show(10, 10)
      但是如果参数类型不是十分确定,或者说,在将来可能大量使用到event的其他数据时
      就不是十分使用;
    2. 如果直接传入event作为参数,那么如果想在其他地方调用myApp.show()方法,就必须创建
      一个event对象传减去;

    应看情况而定;

    8各种值的检测

    1. 简单数据类型的检测:用typeof运算符
    2. 函数用typeof运算符
    3. 数组用Array.isArray()方法
    4. 其他内置对象或自定义的实例对象用 instanceof 运算符
    5. 属性是否存在(包括原型链上的)用 in 元素符
    6. 只是实例对象,不包括原型链上的属性检测用: Object.hasOwnProperty('属性名')
        typeof '123' 返回'string'
        typeof 123 返回 'number'
        typeof true 返回 "boolean"
        typeof undefined 返回 'undefined'
        typeof myFunction 返回 'function'
        Array.isArray([]) 返回 true
    
        //instanceof不仅检测该对象的构造器,还会检测原型链的
        value instanceof Date  ; //日期类型
        value instanceof REGEXp ; //正则表达式
        value instanceof Person ; // Person是自定义的构造函数
    
        // in运算符会检测属性是否存在,包括原型链上的属性
        var obj = {
            count: 12,
            age: 22
        };
        'count' in obj 返回true;
    
        //obj.hasOwnProperty只判断当前实例对象是否含所有该属性,不包括原型链;
        obj.hasOwnProperty('count') 返回true;
    

    9将配置数据从代码中分离出来

    1. 哪些是配置数据
      1. url
      2. 要展示给用户的字符串
      3. 重复的值
      4. 设置,(比如每一页的配置项)
      5. 任何可能发生变化的值;
    2. 怎么分离

    将分离出来的数据存放在一个对象中

    var config = {
        MSG-value: '出错',
        css_selece: 'select',
        url_inval: '/error/a.php',
    }
    

    属性名最好遵循一定的规则;
    3. 存放在哪

    配置数据最好存放在单独的文件中,以便清晰的分离数据和应用逻辑;

    10 抛出自定义错误

    如果要在js中抛出错误,最好用: throw new Error('something bad happened')

    1. 抛出错误 throw new Error("")

    只应该在技术栈的最深层抛出,比如js库,angular框架(内置了很多抛出错误)
    2. 捕获处理错误try{}catch{}

    应用程序的逻辑应该知道调用某个特定函数的原因,因此也适合处理错误,当发生一个错误,
    捕获他,处理他,并让程序好像没有发生错误一样照常运行,这是一个应用逻辑的健壮性的标志;

    11 不是你的对象不要动

    1. 那些是我的
      项目程序逻辑代码创建的对象,是我的.只要维护这段代码是我的责任,那么这段代码创建的对象就是我的
      那些不是我的:

      1. 原生对象
      2. DOM对象
      3. BOM对象
      4. 类库的对象

      原则上来说,不是我的对象,不能覆盖
      ,不能新增(现在没有不代表以后没有),不能删除;

    2. 不是我的的对象怎么修改

      • 最好的方式是集成,
      1. 基于对象的继承
        Object.create(obj);这个方法将返回一个原型是obj的对象;可以有第二个参数
        该参数对象中的属性和方法将添加到新的对象中
        var person = {
            name: 'lifei',
            age: 12,
            sayname: function() {
                console.log(this.name);
            },
        };
        var myPerson = Object.create(person, {
            name: 'lifei2',
        })
        person.sayname();   //输出lifei
        myPerson.sayname();  //输出lifei2;
        
      2. 基于构造函数的继承
        实例是构造函数创建的,而一般的构造函数的原型都是Function,那么把给构造函数的原型改成
        其他对象,
      function Person(name) {
           this.name;
      }
      function Author(name) {
       Person.call(this, name);    //继承构造器
      }
      
      Author.prototype = new Person();
      
      /*
      这段代码里Author类型继承自Person.属性name实际上是有Person类管理的,所以Person.call(this.name)
      允许Person构造器继续定义该属性,Person构造器实在this上执行的this指向一个Author对象
      ,所以最终name定义在Author对象上
      这种方式更灵活,能创建多个;
      */
      
      1. 门面模式
        没看懂,以后再说
    3. 防止扩展,密封,冻结这三种形式,每一种都有两个方法

      1. 防止扩展

      禁止为对象添加属性和方法,但已存在的可以被修改
      Object.preventExtension(person); //防止Person扩展
      Object.isExtensible(person); //判断Person是否可以被扩展
      2. 密封

      类似'防止扩展',并且禁止为对象删除已存在的属性,方法
      Object.seal(person); //密封person对象
      Object.isSealed(person); //判断person对象是否密封

      1. 冻结

      类似'密封',而且禁止为对象修改,属性和方法,(所有的字段都只读)
      Object.freeze();
      Object.isFrozen();

    • 所有试图突破'防止扩展','密封','冻结'的操作在非严格模式下将会悄无声息的失败;
      在严格模式下会报错;
  • 相关阅读:
    CCF真题之Z字形扫描
    CCF真题之门禁系统
    A
    安装 Spring 框架库
    安装 Apache Commons Logging API步骤
    Manven下载
    669. 修剪二叉搜索树
    UnixLinux | 总结笔记 |文件系统
    561. 数组拆分 I
    620. 有趣的电影
  • 原文地址:https://www.cnblogs.com/bridge7839/p/6685716.html
Copyright © 2020-2023  润新知