美文网首页技术文“译”站
[译] Javascript代码约定

[译] Javascript代码约定

作者: NoteCode | 来源:发表于2016-10-27 15:11 被阅读31次

    本文译自Javascript大师Douglas Crockford的文章(2016.10.27版),以飨英文不太好的同学。如果英文过关,建议读原文

    原文 Code Conventions for the JavaScript Programming Language

    排版规则

    粗体:Javascript关键词、操作符等
    斜体:译者补充说明
    部分代码块为译者所加,前面注有:// 译者加

    译文全文

    本文是Javascript编程过程中用到的一系列约定和规则。
    对于一个组织来说,从长远来看,软件的价值与其代码的质量成正比例。在一个程序的整个生命中,会经历很多双眼、很多双手。如果一个程序能清晰的传达其结构和特性,那么未来修改时,这些结构和特性被破坏的可能性会较小。代码约定就是为了降低程序的脆弱性(brittleness)。
    JavaScript代码都是要公开发布的,所以它总是需要具有发布质量。简洁是有价值的。

    JavaScript文件

    应该保存为 .js 文件。
    JavaScript代码不应该嵌入到HTML文件中,除非此代码仅为这一个HTML文件所用(译的欠妥)。将JavaScript嵌入到HTML会增大文件,导致无法通过缓存压缩等机制减小文件。

    空白(Whitespace)

    下面这些规则一直以来都是文字书写的好习惯。除非有明显的好处,否则不应该被打破。

    空行(blank line),将逻辑上有关联的代码放在一块,可以提高可读性。
    空格(blank space),在以下情况中都应该使用:

    • 一个关键词后跟一个 ( 时,应该用一个空格隔开。应用空格,可以使不是调用的地方看起来不像调用(Spaces are used to make things that are not invocations look less like invocations.)。如下例,ifwhile 之后应该有空格:
    while (true) {
    
    • 在function和调用( ( )之间不应该有空格。这样可以将关键词和函数调用区分开来。
    // 译者加
    some_func(a, b);
    
    • 关键词 function 后面总是要跟空格
    // 译者加
    function foo() { ...
    var bar = function () { ...
    
    • 一元操作符和其操作数之间不应该有空格,除非操作符是一个单词,比如 typeof
    // 译者加
    some_var++;
    ++some_var;
    
    • 二元操作符和其操作数之间总是用一个空格隔开,这几个例外:. ( [
    // 译者加
    var c = a + b;
    
    • 逗号 , 之后总是跟空格或换行
    • 用于语句结束的分号 ; 后总是需要换行
    • for 语句中的分号 ; 后总是跟一个空格
    // 译者加
    for (var i = 0; i < 5; i++) {
    

    每一个语句都应该跟当前缩进对齐,最外层缩进对齐编辑区左侧。当上一行的最后一个标识为 { [ ( 时,本行缩进4个空格;相应的关闭标识 } ] ) 应新起一行,缩进减4个空格

    // 译者加
    function foo() {
          while (true) {
              console.log('hello');
          }    
    }
    

    三元操作符看起来比较晕,所以,? 总是新起一行并缩进4个空格,: 也总是新起一行,与 ? 对齐。条件判断需用 ( ) 包起来:

    var integer = function (
          value,
          default_value
    ) {
          value = resolve(value);
          return (typeof value === "number")
              ? Math.floor(value)
              : (typeof value === "string")
                   ? value.charCodeAt(0)
                   : default_value;
    };
    

    如果 . 是一行的第一个字符,缩进4个空格。

    应避免一行过于长。如果一个语句在一行放不下,那就有必要将它分开。最好在 { [ ( ,换行,或者 . ? :换行。如果在这地方换行不合适,那就在操作符之后换行,新行缩进8个空格。但是这8个空格不改变当前缩进。

    块(case catch default else finally)不是语句,故不需要缩进。

    Tab(制表符)和空格不应该混用。二者只选其一,以避免两者都用带来的问题。个人偏好设置并不可靠。Tab空格并不比对方更具优势。50年前,Tab的优势在于节省内存,但摩尔定律已经否定了这一优势(此处不是很懂)空格Tab有一个明确的优势:目前还没有一个可依赖的标准规定一个Tab占几个空格,但毫无争议的是,一个空格确切的占一个空格。所以,总是使用空格。如果必须,你可以在编辑时使用Tab,但确保在提交(commit)时转为空格。或许有一天我们将最终有一个关于Tab的统一标准,不过在那天到来之前,使用空格,是明智的选择。

    注释(Comment)

    应该不吝啬注释。留下一些信息,有助于未来的人(包括你自己)理解你做了什么、为什么要做。注释应该好好写、写清楚,要像写代码一样写注释。一些小幽默也是鼓励的,不过困难和抱怨就不要写了。

    有一点很重要:注释应该保持“新鲜”(up-to-date)。错误的注释反而会使程序更难读、更难懂。

    注释应该有意义,着重说明不能从代码里一眼就看出来的隐含意义。但也不要浪费时间写下面这样的注释:

    i = 0; // 把i设为0
    

    变量声明(Variable Declarations)

    所有的变量都应该在使用之前声明。JavaScript并不强制如此,但这样做可以使程序更易读,并且容易发现未声明的变量可能是隐式的(这句译的欠妥)。隐式的全局变量应该杜绝。尽量少用全局变量。

    推荐:变量的声明语句后跟注释。如果可能,以字母顺序排列:

    var currentEntry; // currently selected table entry
    var level;        // indentation level
    var size;         // size of table
    

    JavaScript中的var没有作用域,故,将变量声明在块(block)中会给有C语言经历的同学造成迷惑。

    函数声明(Function Declaration)

    所有的function都应该先声明后使用。内部函数(inner function)应跟在var后面(即先声明变量,再声明内部函数),这样可以清楚知道当前作用域(scope)有哪些变量。

    函数名和 ( 之间不应该有空格;){ 之间应该有一个空格。函数体缩进4个空格,} 应和函数声明的那一行开始对齐。

    function outer(c, d) {
        var e = c * d;
        var x;  // no use
    
        function inner(a, b) {
            return (e * a) + b;
        }
    
        return inner(0, 1);
    }
    

    这样的约定很适合JavaScript,因为在Javascript中函数和object定义(object literal)可以在任何可以放表达式的地方。可以最大程度的提高内部函数和复杂结构的可读性。

    function getElementsByClassName(className) {
        var results = [];
        walkTheDOM(document.body, function (node) {
            var array;                // array of class names
            var ncn = node.className; // the node's classname
    
    // If the node has a class name, then split it into a list of simple names.
    // If any of them match the requested name, then append the node to the list of results.
    
            if (ncn && ncn.split(" ").indexOf(className) >= 0) {
                results.push(node);
            }
        });
        return results;
    }
    

    如果是匿名函数,在关键词 function( 之间应该有一个空格。如果没有,看起来好像这个函数的名字是function,这当然是错误的解读。

    div.onclick = function (e) {
        return false;
    };
    
    that = {
        method: function () {
            return this.datum;
        },
        datum: 0
    };
    

    应尽量少用全局函数

    如果一个函数被即刻调用(to be invoked immediately),那么整个调用表达式应用 ( ) 包起来,以清楚地表达:产生的值是函数执行的结果,而非函数本身

    var collection = (function () {
        var keys = [];
        var values = [];
    
        return {
            get: function (key) {
                var at = keys.indexOf(key);
                if (at >= 0) {
                    return values[at];
                }
            },
            set: function (key, value) {
                var at = keys.indexOf(key);
                if (at < 0) {
                    at = keys.length;
                }
                keys[at] = key;
                values[at] = value;
            },
            remove: function (key) {
                var at = keys.indexOf(key);
                if (at >= 0) {
                    keys.splice(at, 1);
                    values.splice(at, 1);
                }
            }
        };
    }());
    

    命名(Names)

    名字应该由26个字母的大小写(A...Z, a...z),10个数字(0...9),以及下划线:_ 组合而成。避免使用国际字符,因为他们可能被误读。不要使用 $ 和 \

    不要将 _ 用于名字首字母。这样做有时是为了表示“私有”(privacy),但并不能真正的提供私有(保护)。如果私有很重要,应使用闭包(closure)。避免使用这种名不副实的做法。

    绝大多数变量名和function名应该以小写字母开头。

    必须用 new 调用的构造函数(constructor function),名字应该以大写字母开头。如果 new 缺失,JavaScript并不视为一个编译时(compile-time)错误,也不视为一个运行时(run-time)错误,但却可能有非预期的结果。首字母大写是我们唯一的保护机制。

    全局变量应该全部用大写字母组成。

    语句(Statements)

    简单语句(Simple Statements)

    一行应最多包含一个语句。每一个简单语句都应以 ; 结束。注意:函数定义(function literal)或对象定义(object literal)的赋值语句(assignment statement)也是赋值语句,故也应以 ; 结束。

    // 译者加
    var foo = {
        name: 'x'
    };
    
    var bar = function () {
        return 'bar';
    };
    

    JavaScript允许任何表达式(expression)作为语句(statement)使用。这会掩盖一些错误,有 ; 时更甚。可以作为语句的表达式仅建议:赋值调用delete

    复合语句(Compound Statements)

    复合语句:由 { } 包起来的一系列语句

    • 包起来的语句应缩进4个空格
    • { 应该在复合语句开始的那一行行尾
    • } 应该新起一行,并与相应的 { 所在行行首对齐
    • { } 应包起所有的语句,即使只有一条语句(当它作为控制结构(control structure)的一部分时,比如 if for),这样可以避免后续添加语句时引入错误。
    // 译者加
    if (true) {
          console.log('true');
          // do_some_th
    } else {
          console.log('false');
    }
    
    标签(Labels)

    应避免使用语句标签。只有下面语句才可应用:while do for switch

    return语句

    返回的值表达式(value expression)必须与 return 关键词在同一行,以避免插入 ; (后半句不很懂)

    if语句

    if 类的语句应该有如下形式:

        if (condition) {
            statements
        }
        
        if (condition) {
            statements
        } else {
            statements
        }
        
        if (condition) {
            statements
        } else if (condition) {
            statements
        } else {
            statements
        }
    
    for语句

    for 类的语句应该有如下形式:

        for (initialization; condition; update) {
            statements
        }
    
    while语句

    while 语句应该有如下形式:

        while (condition) {
            statements
        }
    
    do语句

    do 语句应该有如下形式:

        do {
            statements
        } while (condition);
    

    跟其他复合语句不同的是:do 语句总是以 ; 结束

    switch语句

    switch 语句应该有如下形式:

        switch (expression) {
        case expression:
            statements
        default:
            statements
        }
    

    caseswitch 对齐,以避免缩进太多。因 case 不是语句,故不需要“像”语句。

    每一组statements(default除外)都应该以 break / return / throw 结束。不应穿透(fall through)

    continue语句

    避免使用该语句。因它会使控制流(control flow)不清晰。

    with语句

    不应该使用

    { } 和 [ ]

    使用 { } ,而不用 new Object()。
    使用 [ ] ,而不用 new Array()。
    当成员的名字是整数序列时,使用数组(array)。
    当成员的名字是无序字符串或名字时,使用对象(object)。

    逗号操作符(, Operator)

    不应使用逗号操作符。(并不是指我们广泛使用的逗号分隔符

    赋值表达式(Assignment Expressions)

    避免在 if while 语句的条件判断中进行赋值操作 ,下面这句:

    if (a = b) {
    

    是正确的吗?还是下面这句:

    if (a == b) {
    

    才是本意?所以,应避免这种容易引起歧义的写法

    === and !== 操作符

    请使用 ===!== 操作符。==!= 有强制转换,应避免使用。

    引起混淆的加号、减号

    不要在 + 后面跟另一个 +++,因这种做法会引起混淆。而是应该加上 **( ) ** ,以清晰表达你的意图。

    total = subtotal + +myInput.value;
    

    最好改写为:

    total = subtotal + (+myInput.value);
    

    如此,+ + 就不会误读为 ++

    eval是恶魔(eval is Evil)

    eval 函数是JavaScript中最被误用的,不要用它。
    eval 有别名。(不很懂)
    不要使用 Function 构造函数。(不很懂)
    不要给 setTimeout setInterval 传字符串。

    用心编程,你也能长满大胡子 ;)


    800px-Douglas_Crockford.jpg

    相关文章

      网友评论

      • sarry:可惜,我不会长胡子 :scream:
      • michael_jia:原文有不少例子;例子还是很能帮助说明问题的;有时看不懂文字,但能看懂代码。

      本文标题:[译] Javascript代码约定

      本文链接:https://www.haomeiwen.com/subject/wrnjuttx.html