Easiest way to understand Javascript

Lời nói đầu

Lý do để viết bài này thực sự rất đơn giản. Sau một vài năm lập trình frontend và làm việc với Javascript, tôi nhận thấy được một sự thật: Javascript là một ngôn ngữ mềm dẻo, nhưng quái dị (dù tôi thích nó). Có rất rất nhiều bài viết trên mạng về ngôn ngữ này, nhưng hãy thay đổi suy nghĩ một chút, tôi sẽ chỉ cho bạn thấy, cách dễ dàng nhất để bạn sẽ hiểu ngôn ngữ này là như thế nào.

Let's start!

Javascript compiler

Khi bắt đầu học một ngôn ngữ mới, chúng ta thường được dạy cách khai báo biến là như thế nào. Việc khai báo biến thật dễ! Chúng ta ai cũng bị lừa như thế. Tại sao tôi lại gọi như vậy? Bởi vì bạn sẽ khai báo được một biến, nhưng sẽ không thể hình dung được tại sao lại khai báo như thế, và hiểu được cách mà chương trình chúng ta chạy.

Đầu tiên, hãy nhìn vào hai đoạn code bên dưới, và dành một phút để đoán xem kết quả ra gì.

var x = 3;
function myFunc(y) {
    if (y) {
        var x = 5;
        return x;
    }
    return x;
}
myFunc(false);
var x = 3;

function myFunc(y) {
    return x;
}

myFunc(false);

Hết giờ!

Kết quả của hai đoạn code lần lượt là undefined3. Tại sao lại như vậy?
Khoan hãy quan tâm tới kết quả, hãy quay lại câu hỏi ở trên của tôi. Tại sao tôi lại bảo, học cách khai báo biến như trên trường dạy lại là một cú lừa ngoạn mục? Đó là bởi vì bạn đang đứng ở góc độ của một lập trình viên để hiểu được code chính mình viết ra. Toàn bộ mấu chốt của bài viết này nằm ở chỗ, hãy đứng ở vị trí của trình biên dịch.

Nói một chút về trình biên dịch, tôi hiểu một điều rất rõ ràng, Javascript là một ngôn ngữ thông dịch, tuy nhiên bạn hãy thử tưởng tượng mình đang là một trình biên dịch ngôn ngữ Javascript. Hãy nghĩ đơn giản, trình biên dịch sẽ làm các bước như sau:

  • Đọc mã nguồn, thực chất là đọc một chuỗi rất rất dài.
  • Phân tích chuỗi thành những phần nhỏ hơn gọi là token.
  • Sắp xếp lại chúng theo thứ tự, và convert thành 1 đoạn chuỗi "hoàn chỉnh" để phần cứng "hiểu" được.

Chú ý, đây là những suy nghĩ ngô nghê của một đứa trẻ 5 tuổi về cách mà một trình biên dịch làm.

Quay lại với 2 đoạn code ở trên. Đối với trình biên dịch ngôn ngữ Javascript, nó có 1 vài nguyên tắc như sau:

  • Thế giới của Javascript là Object, hàm (function) cũng chỉ là một Object. Điều đó thể hiện rõ ràng ở chỗ, mọi biến đều chỉ có ý nghĩa trong function/object gần nhất chứa nó. Và object lớn nhất trong tất cả các object là window.
  • Khi gặp một function hoặc 1 Object, nó sẽ đọc code nằm trong function/Object đó, và tìm ra những phép gán, và sẽ hô biến biểu thức gán đó theo trình tự như sau:

    • Tách biểu thức gán đó thành 2 biểu thức, 1 là khai báo, 1 là gán.
    • Tiếp đó trình biên dịch còn làm một việc thần thánh hơn là kéo tất cả biểu thức khai báo lên trên cùng của đoạn code nằm trong function/Object đó. Quá trình này gọi là hoisting. Nói cách khác, việc khai báo luôn xảy ra đầu tiên, áp dụng cho cả biến lẫn hàm. Đó là lý do tại sao khi lập trình Javascript, người ta luôn khuyên nên khai báo biến/hàm lên trên cùng.

    Cụ thể, ví dụ với một đoạn code sau

    function() {
        // some code
        var x = 3;
        // some another code
        var y = 5;
        // some another stupid code
        var z;
        // some another super stupid code, too
        z = 7;
        var t;
        // some unrelated code ....
    }
    

    sẽ được hô biến thành như sau

    function() {
        var x, y, z, t;
        // some code
        // some another code
        y = 5;
        // some another stupid code
        // some another super stupid code, too
        z = 7;
        // some unrelated code ....
    }
    

    Để cho dễ hình dung, tôi vẫn để lại y chang thứ tự các đoạn comment :)
    Quá trình này sẽ giải thích những khái niệm như scope, hoisting.

Quay lại với đoạn code ban đầu, và với cách biên dịch đó, thì đoạn code đầu tiên sẽ thành như thế này đây:

var x = 3;
function myFunc(y) {
    var x;

    if (y) {
        x = 5;
        return x;
    }
    return x;
}
myFunc(false);

Những điều cần hiểu ở đây:

  • Vì cái if đầu tiên là false, nên phép gán x=5 sẽ không được thực thi. Khi đó, vì x trong hàm myFunc chưa được gán, nên giá trị sẽ là undefined.
  • Nếu như không có khai báo từ khóa var x nằm trong hàm myFunc, thì biến x khi đó sẽ lấy giá trị của biến x ở ngoài hàm myFunc. Điều này tương tự như những gì trường học dạy, giá trị biến toàn cục có thể ảnh hưởng đến toàn bộ, và được sử dụng ở nhiều nơi. Vì vậy, nên hạn chế xài biến toàn cục là vậy. Và điều này cũng giải thích kết quả của đoạn code thứ hai của chúng ta.

Một vài chú ý

  • Khi ES6 ra mắt, từ khóa letconst ra đời giúp giải quyết được một phần vấn đề của từ khóa var, hạn chế được dùng quá nhiều global scope, hay nói cách khác là dùng biến toàn cục. Bạn có thể tự tìm hiểu tại sao nên hạn chế tư tưởng dùng biến toàn cục.
  • Hoisting áp dụng cho hàm có một chút khác biệt giữa hai trường hợp sau: function myFunc() {}var myFunc = function() {}. Trường hợp đầu tiên sẽ được hoisting, và điều đó có nghĩa là hàm myFunc sẽ sử dụng được ngay cả khi khai báo sau.
  • Đây là 1 bài viết rất hay cũng về hoisting. Link bài viết.

TL;DR

Tôi đã cố gắng in đậm hai chỗ trong toàn bộ bài viết để nói về hai thứ:

  • Scope - là vùng mà biến có ý nghĩa.
  • Hoisting - là kéo biểu thức khai báo lên trên cùng.

Và quan trọng nhất, chỗ in đậm đầu tiên, là cách để giúp bạn hiểu hai khái niệm cơ bản, nhưng lại vô cùng quan trọng ở trên.

Bài viết còn rất nhiều thiết sót, rất mong được các bạn góp ý và cùng nhau chia sẻ, hi vọng sẽ gặp lại ở bài viết sau về những khái niệm quan trọng khác như closure, this, vân vân và mây mây.

ShinaBR2 01-10-2018

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

ShinaBR2

14 bài viết.
127 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
71 16
Đây là một vấn đề kinh điển, và có rất nhiều bài viết về nó, tuy nhiên đa phần là dịch từ bản gốc ra và sao chép lại một vài câu lệnh, và câu hỏi t...
ShinaBR2 viết 3 năm trước
71 16
White
47 11
Vào một ngày đẹp trời, khi bạn nhận được yêu cầu phải thiết kế database cho một hệ thống, câu hỏi đầu tiên được đặt ra, quy trình làm ra nó sẽ cụ t...
ShinaBR2 viết 3 năm trước
47 11
White
40 10
Bàn về code thối Hãy tự đặt câu hỏi cho bạn, khi bắt đầu lập trình, bạn nghĩ tới điều gì? Đi phỏng vấn Điều đầu tiên tôi muốn nói về những câu hỏ...
ShinaBR2 viết gần 3 năm trước
40 10
Bài viết liên quan
White
70 8
Tăng sức mạnh cho javascript với lodash Lần này mình sẽ giới thiệu 1 thư viện javascript vô cùng bá đạo có tên là "lodash]1]", có thể nói nó là LI...
Huy Hoàng Phạm viết gần 5 năm trước
70 8
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
14 bài viết.
127 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!