Giới thiệu cuốn Maintainable Javascript 2
1. Comments 1.1. Comment 1 dòng // Ví dụ tốt if (condition) { // if you made it here, then all security checks passed allowed(); } // Không tốt: Không có dòng trống trước comment if (condition) { // if you made it here, then all security checks passed allowed(); } // Không tốt: ...
1. Comments
1.1. Comment 1 dòng
// Ví dụ tốt if (condition) { // if you made it here, then all security checks passed allowed(); } // Không tốt: Không có dòng trống trước comment if (condition) { // if you made it here, then all security checks passed allowed(); } // Không tốt: Sai lề if (condition) { // if you made it here, then all security checks passed allowed(); } // Ví dụ tốt var result = something + somethingElse; // somethingElse will never be null // Không tốt: Không đủ khoảng trống giữa code và comment var result = something + somethingElse;// somethingElse will never be null // Tốt // if (condition) { // doSomething(); // thenDoSomethingElse(); // } // Không tốt: Đoạn này nên dùng comment nhiều dòng // This next piece of code is quite difficult, so let me explain. // What you want to do is determine whether the condition is true // and only then allow the user in. The condition is calculated // from several different functions and may change during the // lifetime of the session. if (condition) { // if you made it here, then all security checks passed allowed(); }
1.2. Comment nhiều dòng
// Ví dụ tốt if (condition) { /* * if you made it here, * then all security checks passed */ allowed(); } // Không tốt: Không có dòng trống trước comment if (condition) { /* * if you made it here, * then all security checks passed */ allowed(); } // Không tốt: Thiếu khoảng trống sau dấu * if (condition) { /* *if you made it here, *then all security checks passed */ allowed(); } // Không tốt: Sai lề if (condition) { /* * if you made it here, * then all security checks passed */ allowed(); } // Không tốt: Không dùng comment nhiều dòng cho comment đuôi var result = something + somethingElse; /*somethingElse will never be null*/
1.3 Sử dụng comment
1.3.1 Sử dụng comment để giải thích rõ nghĩa code
// Không tốt // Khởi tạo count var count = 10; //Tốt // Thay đổi giá trị này sẽ dẫn đến những thay đổi nghiêm trọng var count = 10;
1.3.1.1 Giải thích các đoạn code khó hiểu
// Ví dụ tốt if (mode) { /* * In mode 2 (prototype to prototype and object to object), we recurse * once to do the proto to proto mix. The object to object mix will be * handled later on. */ if (mode === 2) { Y.mix(receiver.prototype, supplier.prototype, overwrite, whitelist, 0, merge); } /* * Depending on which mode is specified, we may be copying from or to * the prototypes of the supplier and receiver. */ from = mode === 1 || mode === 3 ? supplier.prototype : supplier; to = mode === 1 || mode === 4 ? receiver.prototype : receiver; /* * If either the supplier or receiver doesn't actually have a * prototype property, then we could end up with an undefined from * or to. If that happens, we abort and return the receiver. */ if (!from || !to) { return receiver; } } else { from = supplier; to = receiver; }
1.3.1.2 Các đoạn code theo chủ ý của tác giả giống như là có lỗi
while (element &&(element = element[axis])) { // NOTE: assignment if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { return element; } }
1.3.1.3 Hack Browser-Specific
var ret = false; if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) { ret = false; } else if (element[CONTAINS]) { // IE & SAF contains fail if needle not an ELEMENT_NODE if (Y.UA.opera || needle[NODE_TYPE] === 1) { ret = element[CONTAINS](needle); } else { ret = Y_DOM._bruteContains(element, needle); } } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { ret = true; } } return ret;
1.3.1.3 Documentation comment
/** Returns a new object containing all of the properties of all the supplied objects. The properties from later objects will overwrite those in earlier objects. Passing in a single object will create a shallow copy of it. For a deep copy, use `clone()`. @method merge @param {Object} objects* One or more objects to merge. @return {Object} A new merged object. **/ Y.merge = function () { var args = arguments, i = 0, len = args.length, result = {}; for (; i < len; ++i) { Y.mix(result, args[i], true); } return result; };
2. Các câu lệnh và diễn đạt
2.1. Các khối lệnh với cặp dấu ngoặc {}
2.1.1. Cặp dấu ngoặc {} có thể được dùng với tất cả các khối lệnh if, for, while, do…while, try…catch…finally
// Không tốt dù đúng ngữ pháp JavaScript if(condition) doSomething(); // Không tốt dù đúng ngữ pháp JavaScript if(condition) doSomething(); // Ví dụ tốt if (condition) { doSomething(); } // Không tốt dù đúng ngữ pháp JavaScript if (condition) { doSomething(); }
2.1.2. Dùng cặp dấu ngoặc cũng giúp phát hiện lỗi dễ hơn và làm rõ ý định viết của người code.
Ví dụ
if (condition) doSomething(); doSomethingElse();
Nêú dùng cặp dấu ngoặc {} sẽ phát hiện lỗi dễ hơn
if (condition) { doSomething(); } doSomethingElse(); }
Hoặc
if (condition) { doSomething(); doSomethingElse(); }
2.1.3. Căn lề cặp dấu ngoặc
Có 2 cách căn lề cặp dấu ngoặc phổ biến a, Kế thừa từ Java
if (condition) { doSomething(); } else { doSomethingElse(); }
b, Theo kiểu của C#
if (condition) { doSomething(); } else { doSomethingElse(); }
2.1.4. Khoảng trắng với cặp dấu ngoặc
2.1.4.1 Không có khoảng trắng giữa tên lệnh, dấu ngoặc đơn mở và dấu ngoặc nhọn mở
if(condition){ doSomething(); }
2.1.4.2 Có khoảng trắng giữa tên lệnh, dấu ngoặc đơn mở và dấu ngoặc nhọn mở
if (condition) { doSomething(); }
2.1.4.3 Loại 2 thêm vào các khoảng trắng sau dấu ngoặc đơn mở và trước dấu ngoặc đơn đóng
if ( condition ) { doSomething(); }
Tác giả thích loại 2 vì là sự cân bằng giữa loại 1 và 3.
2.2 Câu lệnh switch
2.2.1 Lề
2.2.1.1 Cách dùng phổ biến
switch(condition) { case "first": // code break; case "second": // code break; case "third": // code break; default: // code }
2.2.1.2 Crockford’s Code Conventions và Dojo Style Guide
switch(condition) { case "first": // code break; case "second": // code break; case "third": // code break; default: // code }
2.2.2 Nhảy qua Falling Through
switch(condition) { // obvious fall through case "first": case "second": // code break; case "third": // code /*falls through*/ default: // code }
2.2.3 default
2.2.3.1 Có default dù nó không làm gì
switch(condition) { case "first": // code break; case "second": // code break; default: // do nothing }
2.2.3.2 Không viết default khi nó không làm gì
Khi default không làm gì, không viết nó mà chỉ viết comment //no default. Tác giả khuyến khích dùng cách này vì nó chỉ rõ chủ ý của tác giả là không có default và tiết kiệm bộ nhớ vì không cần dùng thêm cấu trúc không cần thiết.
switch(condition) { case "first": // code break; case "second": // code break; // no default }
2.3. Câu lệnh with
var book = { title: "Maintainable JavaScript", author: "Nicholas C. Zakas" }; var message = "The book is "; with (book) { message += title; message += " by " + author; }
2.4 Vòng lặp for
2.4.1 break
var values = [ 1, 2, 3, 4, 5, 6, 7 ], i, len; for (i=0, len=values.length; i < len; i++) { if (i == 2) { break; // no more iterations } process(values[i]); }
2.4.2 continue
var values = [ 1, 2, 3, 4, 5, 6, 7 ], i, len; for (i=0, len=values.length; i < len; i++) { if (i == 2) { continue; // skip just this iteration } process(values[i]); }
Crockford’s Code Conventions không cho phép dùng continue vì nó có thể được thay thế sử dụng điều kiện và trở nên dễ hiểu, ít khả năng lỗi hơn. Ví dụ trên có thể viết bằng cách khác là:
var values = [ 1, 2, 3, 4, 5, 6, 7 ], i, len; for (i=0, len=values.length; i < len; i++) { if (i != 2) { process(values[i]); } }
. Tác giả khuyến khích tránh continue khi có thể tránh nhưng không loại bỏ nó hoàn toàn.
2.5 Vòng lặp for-in
2.5.1 hasOwnProperty()
Crockford’s Code Conventions yêu cầu và tác giả khuyến khích dùng hasOwnProperty() check để lọc vòng lặp for-in chỉ cho các thuộc tính instance vì for-in trả về cả các thuộc tính instance của object và các thuộc tính kế thừa từ prototype.
var prop; for (prop in object) { if (object.hasOwnProperty(prop)) { console.log("Property name is " + prop); console.log("Property value is " + object[prop]); } }
Khi muốn dùng với prototype chain, bạn nên dùng comment.
var prop; for (prop in object) { // include prototype properties console.log("Property name is " + prop); console.log("Property value is " + object[prop]); }
2.5.2 Dùng for-in với các đối tượng, Không dùng với mảng
// Không tốt var values = [ 1, 2, 3, 4, 5, 6, 7], i; for (i in values) { process(items[i]); }
To be continued...