Khi mới học lập trình, bạn thường nghe về tham chiếu và tham trị. Mặc dù hiểu rõ lý thuyết, nhiều lập trình viên lại ít chú ý đến chúng trong thực tế, đặc biệt khi fix bug. Sau đây chúng ta hãy cùng nhau tìm hiểu kỹ hơn về hai khái niệm này qua các ví dụ trong C#.
Tham chiếu và tham trị là gì?
Tham chiếu
Tham chiếu liên quan đến việc sử dụng một biến để trỏ đến vùng nhớ của một biến khác. Nghĩa là khi chúng ta có một biến tham chiếu, biến này chỉ chứa địa chỉ và “chỉ” đến vùng nhớ của biến khác. Lúc này, bất kỳ sự thay đổi nào được thực hiện trên tham chiếu sẽ ảnh hưởng đến giá trị của biến gốc.
Ví dụ, giả sử bạn có một biến x
có giá trị là 10. Bây giờ, bạn tạo một tham chiếu y
đến x
. Nếu bạn thay đổi giá trị của y
, giá trị của x
cũng sẽ thay đổi theo.
1 | using System; |
Trong ví dụ này, y
là một tham chiếu đến x
, do đó khi giá trị của y
thay đổi, giá trị của x
cũng thay đổi theo và ngược lại.
Tham trị
Ngược lại, tham trị là việc truyền giá trị thực sự của biến vào một biến khác hoặc một hàm. Khi bạn gán giá trị của biến này cho biến khác, một bản sao giá trị của biến được tạo ra và gán vào biến mới. Lúc này, bất kỳ thay đổi nào được thực hiện trên tham trị sẽ không ảnh hưởng đến giá trị của biến gốc.
Ví dụ, khi một bản sao của giá trị biến được tạo ra và sử dụng trong hàm, nó không ảnh hưởng đến biến gốc.
1 | using System; |
Trong ví dụ này, giá trị của x
không bị thay đổi khi truyền vào hàm ChangeValue
vì x
được truyền theo tham trị, tạo ra một bản sao của x
.
Tại sao chúng ta lại ít để ý?
Hai khái niệm này thể hiện rõ nhất khi làm việc với ngôn ngữ C hoặc C++, do đặc thù của các ngôn ngữ này liên quan tới con trỏ và quản lý cấp phát vùng nhớ. Tuy nhiên, với các ngôn ngữ bậc cao như C# và JavaScript, lập trình viên thường không cần trực tiếp quản lý con trỏ, dẫn đến việc ít chú ý hơn đến sự khác biệt giữa tham chiếu và tham trị.
Trong dự án mình đang tham gia, tôi nhận thấy rằng khoảng 40% lỗi ở frontend (đang dùng React) liên quan đến việc quản lý các giá trị trong bộ nhớ không hợp lý. Việc này xuất phát từ việc không hiểu sâu về React và không nắm rõ tham chiếu, tham trị của biến và data. Điều này dẫn đến việc sửa lỗi một chỗ lại làm xuất hiện lỗi ở chỗ khác, tạo ra vòng luẩn quẩn gây tốn kém thời gian và tiền bạc.
Trong JavaScript và C#, chúng ta có hai loại data types chính: kiểu giá trị nguyên thủy và kiểu giá trị tham chiếu. Kiểu giá trị nguyên thủy (tham trị) bao gồm: string, number, boolean, … Kiểu giá trị tham chiếu bao gồm: object, array, function, …
Ví dụ, khi bạn khai báo một object là x
, và bạn gán y = x
, thì lúc này thực chất cả x
và y
đang cùng trỏ tới một vùng nhớ (tham chiếu).
1 | function updateValue(obj) { |
Trong ví dụ này, x
và y
đều trỏ đến cùng một đối tượng. Khi giá trị của y
thay đổi qua hàm updateValue
, giá trị của x
cũng thay đổi theo.
Chúng ta thường nói JavaScript có những điều kỳ quặc, ví dụ như khi so sánh ===
, lúc thì true
, lúc thì false
, không biết đường nào mà lần. Thực ra nếu hiểu bản chất, chúng ta sẽ thấy nó không khó lắm. Ví dụ:
1 | let a = []; |
Qua các ví dụ và giải thích trên, hy vọng các bạn đã hiểu rõ hơn về tham chiếu và tham trị. Việc nắm vững các khái niệm này không chỉ giúp bạn tránh lỗi khi lập trình mà còn tối ưu hóa việc quản lý bộ nhớ và hiệu suất của ứng dụng.