12/08/2018, 16:10

Effective JavaScript - Chapter 1 - Accustoming Yourself to JavaScript (Part V)

JavaScript được thiết kế để mang lại cảm giác quen thuộc. Với cú pháp (syntax) gợi nhớ về Java và hàm dựng vốn dĩ đã phổ biến ở rất nhiều ngôn ngữ scripting (function, array, dictionary và regular expression), JavaScript dường như là một cái gì đó dễ học với bất cứ ai đã có một chút kinh nghiệm về ...

JavaScript được thiết kế để mang lại cảm giác quen thuộc. Với cú pháp (syntax) gợi nhớ về Java và hàm dựng vốn dĩ đã phổ biến ở rất nhiều ngôn ngữ scripting (function, array, dictionary và regular expression), JavaScript dường như là một cái gì đó dễ học với bất cứ ai đã có một chút kinh nghiệm về programming. Và với các programmer ít kinh nghiệm, họ có thể bắt đầu viết các chương trình mà không cần training quá nhiều tại vì lượng khái niệm core trong JavaScript là không quá nhiều.

Việc tiếp cận tuy dễ dàng, nếu muốn thuần thục (master) nó thì sẽ mất khá nhiều thời gian và đòi hỏi sự hiểu biết sâu hơn về ngữ nghĩa, các đặc tính và các idiom hữu hiệu nhất của nó. Mỗi chapter của cuốn sách này sẽ đề cập đến một phạm vi chủ đề khác nhau của effective JavaScript. Chương đầu tiên này bắt đầu với một vài topic cơ bản nhất.

Một trong những tiện lợi của JavaScript chính là khả năng lược bỏ các dấu chấm phẩy kết thúc lệnh (statement-terminating semicolon) (từ giờ ta gọi tắt là DCP):

function Point(x, y) {
    this.x = x || 0
    this.y = y || 0
}

Point.prototype.isOrigin = function() {
    return this.x === 0 && this.y === 0
}

Đoạn code này có thể chạy là nhờ chương trình tự động thêm DCP (automatic semicolon insertion). Chương trình này tự động phát hiện và thêm DCP vào các chỗ bị thiếu. Chính chuẩn ECMAScript đã đặc tả cơ chế này.

Nhưng tương tự như với thao tác ép kiểu ngầm, việc thêm DCP cũng có những cạm bẫy và đơn giản là bạn không thể tránh được việc học các quy tắc. Thậm chí nếu bạn không bao giờ bỏ qua các DCP, sẽ vẫn có những ràng buộc về cú pháp JavaScript mà bạn cần biết. Những ràng buộc này là hệ quả của việc thêm DCP. Tin tốt lành là một khi bạn học các quy tắc về việc thêm DCP, bạn có thể tự do loại bỏ các DCP không cần thiết.

Quy tắc đầu tiên là: Các DCP chỉ được thêm vào trước thẻ }, sau newline hoặc ở cuối đầu vào chương trình.

Nói cách khác, bạn có thể bỏ các DCP ở cuối dòng, cuối block hay cuối chương trình. Những function sau là hợp lệ:

function square(x) {
    var n = +x
    return n * n
}
function area(r) { r = +r; return Math.PI * r * r }
function add1(x) { return x + 1 }

Nhưng function này thì không:

function area(r) { r = +r return Math.PI * r * r } // error

Quy tắc thứ hai là: Các DCP chỉ được thêm khi thẻ đầu vào tiếp theo không được parse.

Nói cách khác, việc thêm DCP là một cơ chế sửa lỗi. Ví dụ, đoạn code:

a = b
(f());

sẽ được coi như là một câu lệnh đơn:

a = b(f());

Có nghĩa là chẳng có DCP nào được thêm vào. Ngược lại, đoạn code:

a = b
f();

sẽ được parse như là hai câu lệnh riêng biệt, bởi vì:

a = b f();

là một lỗi về parsing.

Quy tắc này có một ngụ ý: Bạn phải luôn luôn chú ý tới đoạn bắt đầu của câu lệnh tiếp theo để nhận ra xem là mình có thể bỏ qua DCP hay không. Bạn không thể bỏ qua DCP của một câu lệnh nếu như thẻ khởi đầu của dòng tiếp theo được hiểu như là sự tiếp nối của câu lệnh hiện tại.

Chính xác là có 5 ký tự mà chúng ta cần coi chừng: (, [, +, - và /. Mỗi ký tự thực hiện một chức năng - có thể là một toán tử biểu thức (expression operator) hoặc là một prefix của một câu lệnh, tùy vào ngữ cảnh. Vậy nên hãy coi chừng các câu lệnh kết thúc với một biểu thức giống như câu lệnh gán (assignment statement) ở trên. Nếu dòng tiếp theo bắt đầu với bất cứ ký tự nào trong năm ký tự trên, sẽ không có DCP nào được thêm vào. Trường hợp phổ biến nhất mà điều này xảy ra chính là khi một câu lệnh bắt đầu với dấu ngoặc đơn, giống như ví dụ ở trên. Một trường hợp phổ biến khác chính là khi sử dụng array literal:

a = b
["r", "g", "b"].forEach(function(key) {
    background[key] = foreground[key] / 2;
});

Trông thì có vẻ là hai câu lệnh nhưng do có ký tự [ nên đoạn code trên tương đương với:

a = b["r", "g", "b"].forEach(function(key) {
    background[key] = foreground[key] / 2;
});

Các biểu thức sẽ được thực hiện từ trái qua phải. Chú ý một chút, b["r", "g", "b"] chính là b["b"]. Vì sao thì các bạn tự tìm hiểu một chút nhé             </div>
            
            <div class=

0