zoukankan      html  css  js  c++  java
  • 前端项目-代码开发规范(个人整理版)

    前端代码规范

    基本的格式化

    1.1 缩进层级

    • 使用空格符进行缩进;

    • 四个空格符表示一个缩进层级;

    function demo() {
        console.log('hello world');
    }
    

    1.2 语句结尾

    • 使用分号结尾;
    // 正确的代码
    let name = 'Nicholas';
    function sayName() {
        alert(name);
    }
    
    • 错误实例:因ASI的分号插入规则复杂难记,会造成与原代码不同的执行结果;
    // 原始代码
    function getData() {
        return
        {
            title: '',
            author: ''
        }
    }
    // 分析器会理解成
    function getData () {
        return;
        {
            title: '',
            author: ''
        };
    }
    

    1.3 行的长度

    • 指定一行代码长度限定在80个字符;

    1.4 换行

    • 当一行长度超过最大字符数限制(80个字符),需手动将一行代码拆成两行,且下一行增加两个层级的缩进;
    // 正确做法: 在运算符后换行,第二行追加两个缩进层级
    callAFunction(document, element, window, 'some string value', true, 123,
            navigator);
    
    // 不好的做法:第二行只有一个缩进
    callAFunction(document, element, window, 'some string value', true, 123,
        navigator);
    
    // 不好的做法:在运算符之前换行了
    callAFunction(document, element, window, 'some string value', true, 123
            , navigator);
    
    • 注意:逗号也算一个运算符,应当作为前一行当结尾;

    • 变量赋值时,第二行的位置应当与赋值运算符的位置保持对齐;

    // 正确的做法
    let result = something + anotherThing + yetAnotherThing + somethingElse +
                 anotherSomethingElse;
    // 确保代码的可读性,并能一眼看清折行的上下文
    

    1.5 空行

    • 在方法之间加入空行

    • 在方法中的局部变量和第一条语句之间加入空行

    • 在多行或单行注释之前加入空行

    • 在方法内的逻辑片段之间插入空行,提高可读性

    • 在方法之间加入空行

    // 好的写法
    function anther () {
    
        for (let i = 0; i < wl.length; i++) {
    
            // 内部逻辑
            p = wl[i];
    
            if (s.hasOwnProperty(p)) {
    
                if (merge && type === 'object') {
                    y.min(r[p], s[p]);
                } else {
                    r[p] = s[p];
                }
            }
        }
    }
    
    /*
    *多行注释
    */
    function bather() {}
    

    1.6 命名

    • 驼峰式大小写:小写字母开始,后续每个单词首字母都大写;
    // 好的写法
    let thisIsMyName;
    let anotherletiable;
    let aVeryLongariableName;
    

    1.6.1 变量和函数

    • 变量名需总是遵守驼峰式大小写命名法,且命名前缀为【名词】,以名词做前缀可以让变量与函数区分开来;函数名前缀为【动词】
    // 变量: 好的写法
    let count = 10;
    let myName = 'Nicholas';
    let found = true;
    
    // 不好的写法:变量看起来像函数
    let getCount = 10;
    let isFound = true;
    
    // 函数: 好的写法
    function getName () {
        return myName;
    }
    
    // 不好的写法: 函数看起来像变量
    function theName() {
        return myName;
    }
    
    • 对于函数和方法命名,第一个单词应该式动词;常见的一些使用动词的约定
    动词 含义
    can 函数返回一个布尔值
    has 函数返回一个布尔值
    is 函数返回一个布尔值
    get 函数返回一个非布尔值
    set 函数用来保存一个值

    1.6.2 常量

    • 常量使用大写字母和下划线来命名,下划线用以分割单词
    let MAX_COUNT = 10;
    let URL = 'http://www.nczonline.net/';
    

    1.6.3 构造函数

    • 构造函数以'驼峰式大小写'命名,首字母为大写,名词
    // 好的做法
    function Person(name) {
        this.name = name
    }
    
    Person.prototype.sayName = function() {
        alert(this.name);
    };
    
    let me = new Person('Nicholas')
    

    1.7 直接量

    1.7.1 字符串

    • 静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。并从头到尾保持一种风格
    // 不好的写法
    const a = "foobar";
    const b = 'foo' + a + 'bar';
    
    // 可接受的写法
    const c = `foobar`;
    
    // 好的写法
    const a = 'foobar';
    const b = `foo${a}bar`;
    const c = 'foobar';
    

    1.7.2 数字

    • 在js中不可省略小数部分或者整数部分
    // 整数
    let count = 10;
    
    // 小数
    let price = 10.0;
    let price = 10.00;
    
    // 不推荐的小数写法:没有小数部分
    let price = 10.;
    
    //不推荐的小数写法: 没有整数部分
    let price = .1;
    
    //不推荐的写法: 八进制写法已经被弃用了
    let num = 010;
    
    // 十六进制写法
    let num = 0xA2
    
    // 科学计数法
    let num = 1e23;
    

    1.7.3 null

    • null是个特殊值,切勿与undefind搞混;
    • null用来初始化一个变量,这个变量可能赋值为一个对象;
    • null用来和一个已经初始化的变量比较,这个变量有可能是也可能不是一个对象;
    • 当函数的参数期望是对象时,用作参数传入;
    • 当函数的返回值期望是对象时,用作返回值传出;
    • 不要使用null来检测是否传入了某个参数;
    • 不要用null来检测一个未初始化的变量
    // 好的用法
    let person = null;
    
    // 好的用法
    function getPerson() {
        if (condition) {
            return new Person('Nicholas')
        } else {
            return null;
        }
    }
    
    // 好的用法
    let person = getPerson()
    if (person !== null) {
        doSomething();
    }
    
    // 不好的写法: 用来和未初始化的变量比较
    let person;
    if (person !== null) {
        doSomething();
    }
    
    // 不好的写法: 检测是否传入了参数
    function doSomething(arg1, agr2, arg3, arg4) {
        if (arg4 !== null) {
            doSomethingElse();
        }
    }
    
    • 理解null最好的方式时将它当作对象的占位符;

    1.7.4 undefined

    • 未被初始化的变量都有一个初始值,即undefined;表示这个变量等待被赋值
    // 不好的写法
    let person;
    console.log(person === undefined); // true
    
    • 尽量避免在代码中使用undefined,这个值常常与返回'undefined'的typeof运算符混淆。
    // foo未被声明
    let person;
    console.log(typeof person); // 'undefined'
    console.log(typeof foo);    // 'undefined'
    
    • 通过禁止使用特殊值 undefined, 可以有效的保证只有一种情况下typeof才会返回'undefined'。如果使用了一个可能(或不可能)赋值为一个对象的变量时,则将其赋值为null。
    // 好的做法
    let person = null;
    console.log(person === null);   // true
    

    1.7.5 对象直接量

    • 对象直接量允许将所有的属性都括在一对花括号中;
    // 好的写法
    let book = {
        title: '',
        author: ''
    }
    
    // 不好的写法
    let book = new Object();
    book.title = '';
    book.author = '';
    
    • 单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。
    // bad
    const a = { k1: v1, k2: v2, };
    const b = {
      k1: v1,
      k2: v2
    };
    
    // good
    const a = { k1: v1, k2: v2 };
    const b = {
      k1: v1,
      k2: v2,
    };
    
    • 对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法。
    // bad
    const a = {};
    a.x = 3;
    
    // if reshape unavoidable
    const a = {};
    Object.assign(a, { x: 3 });
    
    // good
    const a = { x: null };
    a.x = 3;
    
    • 如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义。
    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };
    
    • 上面代码中,对象obj的最后一个属性名,需要计算得到。这时最好采用属性表达式,在新建obj的时候,将该属性与其他属性定义在一起。这样一来,所有属性就在一个地方定义了。
    • 另外,对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写。
    var ref = 'some value';
    
    // bad
    const atom = {
      ref: ref,
    
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // good
    const atom = {
      ref,
    
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };
    

    1.7.6 数组直接量

    • 使用两个方括号将数组初始元素括起来,来替代Array的方式创建数组;
    // 好的写法
    let colors = ['red', 'green', 'blur'];
    let numbers = [1,2,3,4];
    
    // 不好的写法
    let color = new Array('red', 'green', 'blur')
    let numbers = new Array(1,2,3,4);
    
    • 使用扩展运算符(...)拷贝数组。
    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
    
    • 使用 Array.from 方法,将类似数组的对象转为数组。
    const foo = document.querySelectorAll('.foo');
    const nodes = Array.from(foo);
    

    1.8 ES6解构赋值

    • 使用数组成员对变量赋值时,优先使用解构赋值。
    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
    
    • 函数的参数如果是对象的成员,优先使用解构赋值。
    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    }
    
    // good
    function getFullName(obj) {
      const { firstName, lastName } = obj;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
    }
    
    • 如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
    // bad
    function processInput(input) {
      return [left, right, top, bottom];
    }
    
    // good
    function processInput(input) {
      return { left, right, top, bottom };
    }
    
    const { left, right } = processInput(input);
    

    2. 注释

    • 代码晦涩难懂
    • 可能被误认为错误的代码
    • 必要但不明显的针对特定浏览器的代码
    • 对于对象、方法或者属性,生成文档是有必要的(使用恰当的文档注释)

    2.1 单行注释

    • 独占一行,用来解释下一行代码,且缩进层级和下一行代码保持一致;
    • 在代码行的尾部的注释,代码结束到注释之间至少有一个缩进,且不超过单行最大字符数限制,如果超过,则放置在代码行的上方;
    // 好的写法
    if (condition) {
    
        // 代码执行逻辑
        allowed();
    }
    
    // 不好的写法:注释之前没有空行
    if (condition) {
        // 代码逻辑
        allowed();
    }
    
    // 不好的写法: 错误的缩进
    if (condition) {
    // 代码执行逻辑
        allowed();
    }
    
    // 好的写法
    let result = something + somethingElse; // 代码执行逻辑
    
    // 不好的写法: 代码和注释之间没有间隔;
    let result = something + somethingElse;// 代码执行逻辑
    

    2.2 多行注释

    • 多行注释之前应当有一个空行,且缩进层级和其描述的代码保持一致;
    // 好的写法
    if (condition) {
    
        /*
        * 代码执行逻辑
        * 代码执行逻辑
        */
        allowed();
    }
    

    2.3 使用注释

    • 当代码不够清晰时添加注释,当代码很明了时不应当添加注释;
    • 添加注释的一般原则是:在需要让代码变的更清晰时添加注释;
    // 不好的写法
    
    // 初始化count
    let count = 10;
    
    // 好的写法
    
    //改变这个值可能会让它变成青蛙
    let count = 10;
    

    3. 语句和表达式

    • 在JavaScript中,不论块语句包含多行代码还是单行代码,都应该使用花括号
    // 好的写法
    if (condition) {
        doSomething();
    }
    
    // 不好的写法
    if(condition)
        doSomething();
    
    // 不好的写法
    if(condition) doSomething();
    
    // 不好的写法
    if (condition) { doSomething(); }
    

    3.1 花括号的对齐方式

    • 推荐使用的花括号对齐风格是:将左花括号放置在块语句的第一句代码的末尾。
    // 好的做法
    if (condition) {
        doSomething();
    } else {
        doSomethingElse();
    }
    

    3.2 块语句间隔

    • 推荐风格:在括左圆括号之前和括右圆括号之后各添加一个空格
    // 好的做法
    if (condition) {
        doSomething();
    }
    

    3.3 switch语句

    • 无论何时都不应该省略default
    // 好的做法
    switch (condithing) {
        case 'first'
            // 代码
            break;
        default:
            // default中没有逻辑
    }
    

    4.变量、函数、运算符、Class

    4.1 变量声明

    • ES6 提出了两个新的声明变量的命令:let和const。其中,let完全可以取代let,因为两者语义相同,而且let没有副作用。
    'use strict';
    
    if (true) {
      let x = 'hello';
    }
    
    for (let i = 0; i < 10; i++) {
      console.log(i);
    }
    
    • 建议不再使用var命令,而是使用let命令取代。
    'use strict';
    
    if (true) {
      console.log(x); // ReferenceError
      let x = 'hello';
    }
    
    • let命令存在变量提升效用,let命令没有这个问题

    • 必须将所有的变量声明放在函数顶部,而不是散落在各个角落

    // 好的做法
    function doSomething(items) {
        let i, len;
        let value = 10;
        let result = value + 10;
    
        for (i = 0; len = items.length; i < len; i++) {
            doSomething();
        }
    }
    
    • 合并let语句,可以让代码更短更快:每个变量的初始化独占一行,赋值运算符应当对齐,没有初始值的变量,应当出现在let语句的尾部;
    // 好的做法
    function doSomething() {
        let value = 10,
            result = value + 10,
            i, len;
        for (i = 0; len = items.length; i < len; i++) {
            doSomething();
        }
    }
    
    • 在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量
    // 不好的写法
    var a = 1, b = 2, c = 3;
    
    // 好的写法
    const a = 1;
    const b = 2;
    const c = 3;
    
    // 最好的写法
    const [a, b, c] = [1, 2, 3];
    
    • 所有的函数都应该设置常量

    4.2 函数

    • 必须先声明javascript函数再使用函数
    // 好的写法
    function doSomething() {
        alert('');
    }
    
    doSomething();
    
    // 不好的写法
    doSomething();
    
    function doSomething() {
        alert('');
    }
    
    • 立即执行函数可以写成箭头函数的形式。
    (() => {
      console.log('Welcome to the Internet.');
    })();
    
    • 那些需要使用函数表达式的场合,尽量用箭头函数代替。因为这样更简洁,而且绑定了 this。
    // bad
    [1, 2, 3].map(function (x) {
      return x * x;
    });
    
    // good
    [1, 2, 3].map((x) => {
      return x * x;
    });
    
    // best
    [1, 2, 3].map(x => x * x);
    
    • 箭头函数取代Function.prototype.bind,不应再用 self/_this/that 绑定 this。
    // bad
    const self = this;
    const boundMethod = function(...params) {
      return method.apply(self, params);
    }
    
    // acceptable
    const boundMethod = method.bind(this);
    
    // best
    const boundMethod = (...params) => method.apply(this, params);
    
    • 简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法
    • 所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数。
    // bad
    function divide(a, b, option = false ) {
    }
    
    // good
    function divide(a, b, { option = false } = {}) {
    }
    
    • 不要在函数体内使用 arguments 变量,使用 rest 运算符(...)代替。因为 rest 运算符显式表明你想要获取参数,而且 arguments 是一个类似数组的对象,而 rest 运算符可以提供一个真正的数组。
    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    
    • 使用默认值语法设置函数参数的默认值。
    // bad
    function handleThings(opts) {
      opts = opts || {};
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

    4.3 严格模式

    • 不要在全局作用域中使用"use strict"
    // 不好的写法
    "use strict"
    function doSomething() {
        // 代码
    }
    
    // 好的写法
    function doSomething() {
        "use strict"
        // 代码
    }
    

    4.4 相等

    • 所有情景下都应当使用全等===和不全等!==

    4.5 原始包装类型

    • 尽量禁止使用原始包装类型(String、Number、Boolean)来创建新对象
    // 不好的做法
    let name = new String('Nicholas');
    let author = new Boolean(true);
    let count = new Number(10);
    

    4.6 Map结构

    • 注意区分 Object 和 Map,只有模拟现实世界的实体对象时,才使用 Object。如果只是需要key: value的数据结构,使用 Map 结构。因为 Map 有内建的遍历机制。
    let map = new Map(arr);
    
    for (let key of map.keys()) {
      console.log(key);
    }
    
    for (let value of map.values()) {
      console.log(value);
    }
    
    for (let item of map.entries()) {
      console.log(item[0], item[1]);
    }
    
    

    4.7 Class

    • 总是用 Class,取代需要 prototype 的操作。因为 Class 的写法更简洁,更易于理解。
    // bad
    function Queue(contents = []) {
      this._queue = [...contents];
    }
    Queue.prototype.pop = function() {
      const value = this._queue[0];
      this._queue.splice(0, 1);
      return value;
    }
    
    // good
    class Queue {
      constructor(contents = []) {
        this._queue = [...contents];
      }
      pop() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
      }
    }
    
    • 使用extends实现继承,因为这样更简单,不会有破坏instanceof运算的危险。
    // bad
    const inherits = require('inherits');
    function PeekableQueue(contents) {
      Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function() {
      return this._queue[0];
    }
    
    // good
    class PeekableQueue extends Queue {
      peek() {
        return this._queue[0];
      }
    }
    

    4.8 模块

    • Module 语法是 JavaScript 模块的标准写法,坚持使用这种写法。使用import取代require。
    // bad
    const moduleA = require('moduleA');
    const func1 = moduleA.func1;
    const func2 = moduleA.func2;
    
    // good
    import { func1, func2 } from 'moduleA';
    
    • 使用export取代module.exports。
    // commonJS的写法
    var React = require('react');
    
    var Breadcrumbs = React.createClass({
      render() {
        return <nav />;
      }
    });
    
    module.exports = Breadcrumbs;
    
    // ES6的写法
    import React from 'react';
    
    class Breadcrumbs extends React.Component {
      render() {
        return <nav />;
      }
    };
    
    export default Breadcrumbs;
    
    • 如果模块只有一个输出值,就使用export default,如果模块有多个输出值,就不使用export default,export default与普通的export不要同时使用。

    • 不要在模块输入中使用通配符。因为这样可以确保你的模块之中,有一个默认输出(export default)。

    // bad
    import * as myObject from './importModule';
    
    // good
    import myObject from './importModule';
    
    • 如果模块默认输出一个函数,函数名的首字母应该小写。
    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
    
    • 如果模块默认输出一个对象,对象名的首字母应该大写。
    const StyleGuide = {
      es6: {
      }
    };
    
    export default StyleGuide;
    

    5. 避免使用全局变量

    • 在浏览器中,window对象往往重载并等同于全局对象,,因此任何在全局作用域中声明点变量和函数都是window对象的属性;

    6.事件处理

    • 最佳实践:将应用逻辑从所有事件处理程序中抽离出来

    • 规则 1: 隔离应用逻辑;

    // 好的写法
    let myApplication = {
        handleClick: function(event) {
            this.showPopup(event)
        },
        showPopup: function(event) {
            let popup = document.getElementById('popup');
            popup.style.left = event.clientX + 'px';
            popup.style.top = event.clientY + 'px';
            popup.className = 'reveal'
        }
    };
    
    addListener(element, 'click', function(event) {
        MyApplication.handleClick(event);
    });
    
    • 规则 2: 不要分发事件对象, 最佳点办法是让事件处理程序使用event对象来处理事件;然后拿到所需要的数据传给应用逻辑
    // 好的写法
    let myApplication = {
        handleClick: function(event) {
            this.showPopup(event.clientX, event.clientY)
        },
        showPopup: function(x,y) {
            let popup = document.getElementById('popup');
            popup.style.left = x + 'px';
            popup.style.top = y + 'px';
            popup.className = 'reveal'
        }
    };
    
    addListener(element, 'click', function(event) {
        MyApplication.handleClick(event);
    });
    
    

    7. 避免空比较

    let Controller = {
        process: function(items) {
            if (items !== null) {   // 不好的写法
                items.sort();
                items.forEach(function() {
                    // 执行逻辑
                })
            }
        }
    }
    

    7.1 检测原始值

    • javascript有五种原始类型:字符串、数字、布尔值、null、undefined
    • 判断五种原始类型,最好使用typeo运算符;
    • typeof运算符会返回一个表示值的类型的字符串
    // 检测字符串
    if (typeof name === 'string') {
        anotherName = name.substring(3);
    }
    
    // 检测数字
    if (typeof count === 'number') {
        updateCount(count);
    }
    
    // 检测布尔值
    if (typeof found === 'boolean' && found) {
        message('Found');
    }
    
    // 检测undefined
    if (typeof MyApp === 'undefined') {
        MyApp = {}
    }
    
    • 未定义到变量和值为undefined的变量,通过typeof都将返回'undefined'
    • 原始值 null ,一般不用于检测语句,如果需要检测null,最好使用===或!==
    typeof null 返回 'object'
    编程时需要杜绝使用typeof来检测null的类型
    

    7.2 检测引用值

    • 检测某个引用值的类型的最好方法是使用instanceof运算符
    value instanceof constructor
    
    // 检测日期
    if (value instanceof Date) {
        console.log(value.getFullYear());
    }
    
    // 检测正则表达式
    if (value instanceof RegExp) {
        if (value.test(anotherValue)) {
            console.log('Mathces');
        }
    }
    
    // 检测Error
    if (value instanceof Error) {
        throw value;
    }
    
    • instanceof运算符可用于检测自定义的类型
    function Person(name) {
        this.name = name;
    }
    let me = new Person('Nicholas');
    
    console.log(me instanceof Object); // true
    console.log(me instanceof Person); // true
    

    7.2.1 检测函数

    • javascript中的函数都是引用类型,同样存在Function构造函数,每个函数都是其实例;
    function myFunc() {};
    
    // 不好的写法
    console.log(myFunc instanceof Function); // true
    // 然而这个方法不能跨帧(frame)使用,因为每个帧都有各自的Function构造函数。但是可以使用typeof运算符检测函数
    
    // 好的写法
    console.log(typeof myFunc === 'function')
    

    7.3 检测属性

    • 判断属性是否存在的最好办法是使用in运算符

    • in运算符仅仅会简单的判断属性是否存在,而不会去读取属性到值

    let object = {
        count: 0,
        related:null
    }
    
    // 好的写法
    if ('count' in object) {
        // 这里的代码会执行
    }
    
    // 不好的写法: 检测假值
    if (object['count']) {
        // 这里的代码不会执行
    }
    
    // 好的写法
    if ('related' in object) {
        // 这里的代码会执行
    }
    
    // 不好的写法: 检测是否为null
    if (object['related'] !== null) {
        // 这里的代码不会执行
    }
    
    • 检测实例对象的某个属性是否存在,则使用hasOwnProperty()方法,如果实例存在这个属性则返回true(如果这个属性只存在于原型里,则返回false)
    // 对于所有非dom对象,这是最好的办法
    if (object.hasOwnProperty('related')) {
        // 执行这里的代码
    }
    
    // 如果不确定是否为dom对象,
    if ('hasOwnProperty' in object && object.hasOwnProperty('related')) {
        // 执行这里的代码
    }
    

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

    8.1 什么是配置数据

    • 配置数据是应用中写死的值
    function validate(value) {
        if (!value) {
            alert('Invalid value')  // 可能会修改替换
            location.href = '/errors/invalid.php';  // 可能会修改替换
        }
    }
    
    function toggleSelected(element) {
        if (hasClass(element, 'selected')) {    // 'selected' 可能会修改替换
            removeClass(element, 'selected');   // 'selected' 可能会修改替换
        } else {
            addClass(element, 'selected')   // 'selected' 可能会修改替换
    
        }
    }
    
    • URL
    • 需要展现给用户的字符串
    • 重复的值
    • 设置(比如每页的配置项)
    • 任何可能发生变更的值

    8.2 抽离配置数据

    • 将配置数据从代码中抽离出来的第一步是将配置数据拿到外部,即将数据从JavaScript代码之中拿掉
    let config = {
        MSG_INVALID_VALUE: 'Invalid value',
        URL_INVALID: 'errors/invalid.php',
        CSS_SELECTED: 'selected'
    }
    function validate(value) {
        if (!value) {
            alert(config.MSG_INVALID_VALUE);
            location.href = config.URL_INVALID;
        }
    }
    function toggleSelected(element) {
        if (hasClass(element, config.CSS_SELECTED)) {    // 'selected' 可能会修改替换
            removeClass(element, config.CSS_SELECTED);   // 'selected' 可能会修改替换
        } else {
            addClass(element, config.CSS_SELECTED)   // 'selected' 可能会修改替换
    
        }
    }
    

    8.3 保存配置数据

    • 配置数据最好放在单独的文件中,以便清晰的分隔数据和应用逻辑
    • 将配置文件置于单独的JavaScript文件中,是一个不错的开始。一旦配置数据存放于单独的文件中,就可以管理这些数据

    9. 抛出自定义错误

    9.1 在JavaScript中抛出错误

    • 使用throw操作符,将提供的一个对象作为错误抛出。
    • 任何类型的对象都可以作为错误抛出,Error对象是最常用的

    throw new Error('something bad happend')

      // 不好的写法
      throw 'message';
    
    • 如果没有通过try-catch语句捕获,抛出任何值将引发一个错误
    • 唯一不出差错的显示自动移动错误消息的方式就是使用一个Error对象

    9.2 抛出错误的好处

    • 抛出自己的错误可以使用确切的文本供浏览器显示
    • 在错误消息中包含函数名称以及函数失败的原因

    9.3 何时抛出错误

    • 一旦修复了一个很难调试的错误,尝试增加一两个自定义错误,当再次发生错误时,这将有帮助于更容易的解决问题
    • 如果正在编写代码,思考一下:“我希望【某些事情】不会发生,如果发生,我的代码会一团糟糕”。这时,如果“某些事情”发生,就抛出一个错误
    • 如果正在编写的代码别人也会使用,思考一下他们的使用方式,在特定的情况下抛出错误

    请牢记,我们多目的不是防止错误,而是在错误发生时能更加容易的调试

    9.4 try-catch语句

    • 将可能引发错误的代码放在try块中,处理错误的的代码放在catch块中
    try {
        somethingThatMighCauseAnError();
    } catch (ex) {
        handleError(ex)
    }
    

    当try块中发生一个错误时,程序立即停止执行,然后跳到catch块,并传入一个错误对象。检测该对象可以确定从错误中恢复的最佳动作。

    • 可以增加finally块。finally块中的代码不管是否有错误发生,最后都会被执行。
    try {
        somethingThatMighCauseAnError();
    } catch (ex) {
        handleError(ex)
    } finally {
        continue;
    }
    

    注意:如果try块中包含了一个return语句,实际上必须等到finally块中的代码执行后才能返回,因此,finally其实不太常用,但是如果处理错误必要,它仍是处理错误的一个强大工具;

    • 使用throw还是try-catch
    • 千万不要将try-catch中的catch留空,需写点错误处理逻辑来处理错误。
    // 不好的写法
    try {
        somethingThatMighCauseAnError();
    } catch (ex) {
        // 空
    }
    

    9.5 错误类型

    • Error: 所有错误的基本类型;

      • EvalError: 通过eval()函数执行代码发生错误时抛出;
      • RangeError: 一个数字超出它的边界时抛出;
      • SyntaxError: 期望的对象不存在时抛出;
      • TypeError: 变量不是期望的类型时抛出;
      • URIError: 给encodeURL()、encodeURLComponent()、decodeURL()等函数传递格式非法的URL字符串时抛出;
    • 创建自己的错误类型,继承Error,这种做法允许你提供额外的信息,同时可区别与浏览器抛出的错误。

    function MyError(message) {
        this.message = message;
    }
    MyError.prototype = new Error();
    
    这段代码有两个重要的部分:message属性,浏览器必须要知道错误消息字符串;设置prototype为Error的一个实例,对JavaScript引擎就标识它是一个错误对象;
    

    throw new MyError('Hello world');

    10. 文档化 JSDOC

    • JSDoc是一个根据javascript文件中注释信息,生成JavaScript应用程序或库、模块的API文档 的工具
    • JSDoc注释一般应该放置在方法或函数声明之前,它必须以/ **开始,以便由JSDoc解析器识别。其他任何以/*,/***或者超过3个星号的注释,都将被JSDoc解析器忽略
    /**
     * Book类,代表一个书本.
     * @constructor
     * @param {string} title - 书本的标题.
     * @param {string} author - 书本的作者.
     */
    function Book(title, author) {
        this.title=title;
        this.author=author;
    }
    Book.prototype={
        /**
         * 获取书本的标题
         * @returns {string|*}
         */
        getTitle:function(){
            return this.title;
        },
        /**
         * 设置书本的页数
         * @param pageNum {number} 页数
         */
        setPageNum:function(pageNum){
            this.pageNum=pageNum;
        }
    };
    

    学习文档:JSDoc中文文档

    学习资料《编写可维护的JavaScript》《ECMAScript 6入门》

  • 相关阅读:
    入门练习
    课堂作业补充
    例题作业(9.1-9.7)
    stream — 创建stream(一)
    Lambda表达式的四大内置核心函数式接口
    lambda表达式基础语法及其使用
    java 按照固定大小分割 list 集合的几种方式
    分布式锁相关解决方案
    zabbix3.0 使用详解
    eclipse Memory Analyzer (mat) 安装及使用
  • 原文地址:https://www.cnblogs.com/webSciprt/p/9566759.html
Copyright © 2011-2022 走看看