Google JavaScript Style Guide 中文简要翻译 – Language Rules部分

组内计划依照Google的JavaScript编程规约来进行开发。非常认真的学习了一下,于是顺手简单地翻译成了中文。
Style Rules部分等有空再翻。因为是原创,虽然可能别人也翻译过了,但转载时仍请注明出处。

余刚学习JavaScript不久,不可避免对原文的理解有错误,如有错误或不当地方请指出。

Google JavaScript Style Guide 中文简要翻译

1. Language Rules部分

1.1 var
总是使用var声明变量。(理由不多说了)

1.2 Constants
使用大写字母和下划线『_』来声明常量。可以在注释中适当使用@const标签。
但不要使用const限定词来修饰变量。IE浏览器不会解析const。
例如,对于简单的类型,命名规则已经足够:

/**
 * The number of seconds in a minute.
 * @type {number}
 */
goog.example.SECONDS_IN_A_MINUTE = 60;

对于复杂类型,使用@const标签:

/**
 * The number of seconds in each of the given units.
 * @type {Object.<number>}
 * @const
 */
goog.example.SECONDS_TABLE = {
  minute: 60,
  hour: 60 * 60
  day: 60 * 60 * 24
}

这允许编译器强制检查是否有改变。

1.3 Semicolons
总是使用分号『;』来结束语句。(理由也不多说了)

1.4 Nested functions
嵌套函数(函数体内定义的函数):可以使用。
嵌套函数有时候非常有用,自己决定在需要时使用。

1.5 Function Declarations Within Blocks
在块中定义函数:不要这样干。
虽然大多数JS解析器支持,但这不是ECMAScript标准。
ECMAScript标准只允许在脚本的全局环境或者函数体内定义函数。
请使用匿名函数并赋值给一个变量来替代。

错误的用法:

if (x) {
  function foo() {}
}

正确的用法:

if (x) {
  var foo = function() {}
}

1.6 Exceptions
应当使用异常处理。异常是不可避免的。

1.7 Custom exceptions
自定义异常:可以使用。自己决定在需要时使用。

1.8 Standards features
为了保持最大兼容,使用标准特性而不要使用非标准特性。
例如使用string.charAt(3)而不是使用string[3]。
又如使用DOM的函数来操作HTML元素而不是使用特定的省略记法。

1.9 Wrapper objects for primitive types
包装内置数据类型:没有理由这样干,而且这样做很危险。

不要这样干:

var x = new Boolean(false);
if (x) {
  alert('hi');  // Shows 'hi'.
}

但类型转换是OK的:

var x = Boolean(0);
if (x) {
  alert('hi');  // This will never be alerted.
}
typeof Boolean(0) == 'boolean';
typeof new Boolean(0) == 'object';

1.10 Multi-level prototype hierarchies
(自定义的)多层原型继承体系:不推荐。
如果你以自定义的类B为原型导出类D,那么你就构造了一个多层原型继承体系。
这些体系比它们乍看起来要难正确使用。

所以,使用Google的Closure库(the Closure Library)中的goog.inherits()或类似的类库来实现。

function D() {
  goog.base(this)
}
goog.inherits(D, B);

D.prototype.method = function() {
  ...
};

注:过长的原型链同时会导致性能问题。

1.11 Method definitions
将方法定义为原型方法。
原型方法定义的例子:

Foo.prototype.bar = function() { ... };

当有多个原型方法要添加时:

Foo.prototype.bar = function() {
  /* 注释 */
};

注:原型方法比构造函数中定义的对象方法效率要高
例如1.11-1的getFullName效率不如1.11-2的getFullName。
1.11-1

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.getFullName = function() {
        return this.firstName + " " + this.lastName;
    };
}

1.11-2

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

Person.prototype.getFullName = function() {
    return this.firstName + " " + this.lastName;
};

1.12 Closures
闭包:可以使用,但要慎重。
这里有一份闭包指南:http://jibbering.com/faq/notes/closures/

要注意到的一点是,一个闭包函数会在它的作用域内保留一个指针。
如果将一个闭包函数赋给DOM元素,会引起循环引用,并导致内存泄漏。例如:

function foo(element, a, b) {
  element.onclick = function() { /* uses a and b */ };
}

闭包函数会保持对element,a和b的引用,即使它从来不使用element。而element也保持对闭包的引用,这构成了一个循环,占用的内存将不会被回收。

应当使用下面的方式代替:

function foo(element, a, b) {
  element.onclick = bar(a, b);
}

function bar(a, b) {
  return function() { /* uses a and b */ }
}

注:闭包可以轻易产生循环引用,导致闭包和在闭包作用域链上的变量都不会被释放。这也正是能够通过闭包方式实现类私有成员的方法之一。对于不涉及DOM/ActiveX元素的闭包,在代码执行完毕后循环引用可以被JS引擎检测到,从而成功释放内存。当加入DOM/ActiveX后,会截断JS引擎的检测,导致内存泄漏。


1.13 eval()
eval()函数:仅应当在反序列化的情况下使用
eval()会导致语义混乱,并且如果执行的代码中含有用户输入时很危险。你可以用更加安全漂亮的代码来实现,所以一般情况下不应当使用它。

反序列化是一个将数据序列写入内存数据结构的过程。(注:比如切换语言时更新字符串)

例如,你的Http页面将会输出一个文件:

users = [
  {
    name: 'Eric',
    id: 37824,
    email: 'jellyvore@myway.com'
  },
  {
    name: 'xtof',
    id: 31337,
    email: 'b4d455h4x0r@google.com'
  },
  ...
];

执行这个文件中的代码可以快速地在内存中重构数据。

类似地,eval()函数可以简化处理RPC响应的过程。比如,发起一个XMLHttpRequest的远程请求,服务器端返回的响应是JavaScript片段时:

var userOnline = false;
var user = 'nusrat';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'http://chat.google.com/isUserOnline?user=' + user, false);
xmlhttp.send('');
// Server returns:
// userOnline = true;
if (xmlhttp.status == 200) {
  eval(xmlhttp.responseText);
}
// userOnline is now true.

1.14 with() {}
with语句:不要使用。
with会导致语义混乱。例如下面的语句会导致什么?

with (foo) {
  var x = 3;
  return x;
}

答:什么都有可能。局部变量x有可能和foo的属性冲突,甚至foo.x存在一个setter,这种情况下即使是将3赋给x,都会导致一大段代码执行。

1.15 this
this指针:仅在对象的构造函数,方法以及闭包的函数体内使用。
this的指向具有迷惑性。因为容易出错,所以必须限制它的使用范围。

1.16 for-in loop
for-in循环:仅当遍历一个对象、map或hash的keys时候使用。
在遍历数组时经常能看到不正确的for-in使用。for-in循环不是从0遍历到length-1,它会遍历对象的所有属性/方法以及原型链上的方法。

不正确的用法:

function printArray(arr) {
  for (var key in arr) {
    print(arr[key]);
  }
}

printArray([0,1,2,3]);  // This works.

var a = new Array(10);
printArray(a);  // This is wrong.

a = document.getElementsByTagName('*');
printArray(a);  // This is wrong.

a = [0,1,2,3];
a.buhu = 'wine';
printArray(a);  // This is wrong again.

a = new Array;
a[3] = 3;
printArray(a);  // This is wrong again.

请使用普通的for循环来遍历数组:

function printArray(arr) {
  var l = arr.length;
  for (var i = 0; i < l; i++) {
    print(arr[i]);
  }
}

注:上面的代码实际上用了一个小技巧,将数组的长度缓存在变量l中,而不是在每次循环中都重新获取。数组长度的getter访问是要时间的,缓存后可以提高效率。

1.17 Associative Arrays
永远不要将Array当成 map/hash/关联数组 来用。

1.18 Multiline string literals
将长字符串换行:不要这样做。

例如,这是错误的写法:

var myString = 'A rather long string of English text, an error message \
                actually that just keeps going and going -- an error \
                message to make the Energizer bunny blush (right through \
                those Schwarzenegger shades)! Where was I? Oh yes, \
                you\'ve got an error and all the extraneous whitespace is \
                just gravy.  Have a nice day.';

使用『+』来连接:

var myString = 'A rather long string of English text, an error message ' +
    'actually that just keeps going and going -- an error ' +
    'message to make the Energizer bunny blush (right through ' +
    'those Schwarzenegger shades)! Where was I? Oh yes, ' +
    'you\'ve got an error and all the extraneous whitespace is ' +
    'just gravy.  Have a nice day.';

1.19 Array and Object literals
使用直接量构造数组或对象,而不是使用构造函数。

例如:

// Length is 3.
var a1 = new Array(x1, x2, x3);

// Length is 2.
var a2 = new Array(x1, x2);

// If x1 is a number and it is a natural number the length will be x1.
// If x1 is a number but not a natural number this will throw an exception.
// Otherwise the array will have one element with x1 as its value.
var a3 = new Array(x1);

// Length is 0.
var a4 = new Array();

尤其是数组a3,x1的不确定性会导致截然不同的结果。
当x1是数字且大于等于0时,会构造具有x1个元素的数组;是数字但不正常时,会抛出一个异常。
当x1是非数字时,会构造只有一个元素的数组,元素的值就是x1。

使用下面的方法来代替:

var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];

对象的构造不存在这样的问题,但为了可读性更强,也应当使用直接量构造。

不太好的构造方法:

var o = new Object();

var o2 = new Object();
o2.a = 0;
o2.b = 1;
o2.c = 2;
o2['strange key'] = 3;

应当这样构造:

var o = {};

var o2 = {
  a: 0,
  b: 1,
  c: 2,
  'strange key': 3
};

1.20 Modifying prototypes of builtin objects
修改内建对象的原型:严格禁止。
例如Object.prototype或Array.prototype是严格禁止修改的,
即使修改Function.prototype不那么危险,但也应当避免。

1.21 Internet Explorer’s Conditional Comments
IE浏览器支持的条件注释:不要使用。
条件注释会阻碍自动化测试工具的工作,因为它们会在运行时改变JavaScript的语法树。

不要这样写:

var f = function () {
    /*@cc_on if (@_jscript) { return 2* @*/  3; /*@ } @*/
};

注:IE会执行JavaScript注释块中的@cc_on代码,
例如下面的代码,IE有输出,其他浏览器都当成了注释:

<html>
<body>
<script type="text/javascript">
/*@cc_on document.write("Hello, JScript!"); @*/
</script>
</body>
</html>

又例如IE支持的HTML条件注释,IE有输出,其他浏览器都当成了注释:

<html>
<body>
<!--[if IE]>
<script type="text/javascript">
 document.write("Hello, JScript!");
</script>
<![endif]--> 
</body>
</html>

Google没有说明是JavaScript还是HTML的条件注释,但因为这是JavaScript的编程规约,应当仅指JavaScript的条件注释。
事实上HTML的条件注释也能导致同样的后果。依据Google的规约,也不应当使用HTML条件注释来特别为IE执行JavaScript代码。
但使用HTML条件注释加载不同的样式表是可以的。

2012年2月6日 | 归档于 程序
  1. 2012年2月12日 15:33 | #1

    感谢大大,果断标记一下先

  2. 2012年2月8日 18:34 | #2

    这学期的新课,标记一下.感谢大大.

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: