Phân biệt tham chiếu và tham trị trong javascript

  • July 13, 2024
  • 110

Tìm hiểu về tham chiếu(reference type) và tham trị(value type) trong javascript. Trong javascript biến có thể lưu trữ các dữ liệu nguyên thuỷ(primitive data) như string, number, boolean... là các dữ liệu kiểu tham trị, hoặc các dữ liệu phức tạp như object, array, function là dữ liệu kiểu tham chiếu. Sự khác biệt chính giữ kiểu dữ liệu tham chiếu và tham trị nằm ở cách chúng được lưu trữ và thao tác trong bộ nhớ. Tham trị biến sẽ lưu trữ giá trị thật. Tham chiếu biến chỉ lưu trữ địa chỉ ô nhớ lưu giá trị thật.

Value type

Tham trị lưu trữ giá trị thật vào trong biến. Biến được gán dữ liệu kiểu tham trị thì biến đó sẽ lưu trữ giá trị vào trong biến luôn. Khi bạn gán một biến tham trị với một biến khác, hoặc truyền nó làm đối số của một hàm thì một bản sao(clone) của giá trị được tạo. Điều này giúp những thay đổi của biến mới sẽ không ảnh hưởng đến biến gốc.

Ví dụ gán một biến tham trị với cho 1 biết khác.


// Biến a được gán một kiểu dữ liệu nguyên thuỷ là number
let a = 5;
// Gán biến b = biến a
let b = a;
// Thay đổi giá trị của biến b
b = 10;
// Khi thay đổi giá trị của biến b, giá trị của biến a không thay đổi. 
// Do khi gán một biến mới với 1 biến tham trị thì một bản sao của giá trị được tạo ra lưu trữ vào biến mới.
// Lúc này thay đổi giá trị của biến mới không ảnh hưởng đến biến gốc.
console.log(a); // Output: 5
console.log(b); // Output: 10

Ví dụ truyền một biến tham trị làm đối số của một hàm.


function modifyNumber(num) {
  num = 42;
}

let originalNum = 10;
modifyNumber(originalNum);
// Giá trị của biến originalNum không bị thay đổi.
console.log(originalNum); // Output: 10

Reference Type

Một biến lưu dữ liệu kiểu tham chiếu thì biến đó không lưu trữ giá trị thật mà chỉ lưu địa chỉ ô nhớ lưu giá trị thật. Khi gán một biến tham chiếu cho một biến khác hoặc truyền nó như đối số của một hàm chúng ta đang truyền tham chiếu đến cùng 1 địa chỉ ô nhớ chứa giá trị thật. Điều này có nghĩa là thay đổi biến này sẽ ảnh hưởng đến biến kia.

Ví dụ gán một biến tham chiếu cho một biến khác


// Biến a được gán giá trị là một array(kiểu dữ liệu tham trị)
let a = [1, 2, 3];
// Gán biến b bằng biến a
let b = a;
// Thay đổi giá trị của biến b
b.push(4);
// Khi thay đổi biến b, giá trị của biến gốc a cũng bị thay đổi. 
// Do biến b và biến a đều tham chiếu đến địa chỉ ô nhớ chứa giá trị của biến a.
// Nên khi biến b thay đổi biến a cũng bị thay đổi theo
console.log(a); // Output: [1, 2, 3, 4]
console.log(b); // Output: [1, 2, 3, 4]

Ví dụ truyền một biến tham chiếu làm đối số của hàm


function modifyArray(arr) {
  arr.push(42);
}

let myArray = [1, 2, 3];
modifyArray(myArray);
// Giá trị của biến bị thay đổi.
console.log(myArray); // Output: [1, 2, 3, 42]

Clone Reference Type

Để thay đổi các biến tham trị không bị ảnh hưởng đế biến gốc cần clone biến gốc, nghĩa là tạo ra một biến mới rồi copy các giá trị của biến cũ cho biến mới. Để thực hiện clone biến tham trị sử dụng toán tử 3 dấu chấm(spread operator).


// Biến ban đầu
let persion = { name: "huunv", age: 18 };
// Biến được clone từ biến gốc
let clonePersion = { ...persion };
// Thay đổi giá trị của biến mới
clonePersion.age = 20;
// Giá trị của biến gốc không thay đổi
console.log(persion.age); // Output: 18
console.log(clonePersion.age); // Output: 20

Khi clone biến mới từ biến gốc thì biến mới sẽ được lưu trong địa chỉ ô nhớ mới và giá trị của biến mới được copy từ biến gốc sang.

Chú ý: khi sử dụng spread oparator thì các giá trị của biến chỉ được copy một từng, nếu biến có nhiều từng cần phải clone hết các từng.


// Object nhiều từng
let product = {
    name: "áo",
    attribute: {
        color: "red"
    }
}
// Clone object
cloneProduct = {
    ...product
}
// Thay đổi giá trị của object
cloneProduct.attribute.color = "blue";
// Khi thay đổi giá trị của biến mới ở tứng thứ 2
// Giá trị của biến gốc cũng bị thay đổi
console.log(product.attribute.color); // Output: blue

// để giá trị của biến không bị thay đổi cần clone nested.
// Clone object
cloneProduct2 = {
    ...product,
    attribute: {
        ...product.attribute
    }
};
// Thay đổi giá trị biến mới
cloneProduct.attribute.color = "white";
// Giá trị của biên cũ không đổi
console.log(product.attribute.color); // Output: red

Tổng kết

Trong javascript có 2 loại dữ liệu tham chiếu(array, object, function) và tham trị là các dữ liệu còn lại. Các biến tham trị lưu trữ giá trị thật của biến, thay đổi giá trị của biến được copy từ biến gốc, không làm thay đổi biến gốc. Các biến tham chiếu lưu địa chỉ ô nhớ chứa giá trị của biến, nên khi copy biên biến mới vẫn có chung địa chỉ với biến gốc, dẫn đến thay đổi giá trị biến mới biến gốc cũng bị thay đổi.