- vừa được xem lúc

Tham chiếu và tham trị trong JavaScript

0 0 24

Người đăng: Thanh Hung

Theo Viblo Asia

Tham chiếu và tham trị là những kiến thức rất quen thuộc và cơ bản nhưng không phải ai cũng có thể hiểu rõ hai khái niệm này dù đã tiếp xúc với JavaScript lâu năm hay mới làm quen.

Kiểu tham trị (Value Types)

Kiểu này dùng cho các kiểu dữ liệu nguyên thuỷ: String, Number, Boolean, BigInt, Symbol, undefined, null. Kiểu này thì cũng khá là đơn giản, khi gán cho nó một giá trị thì nó sẽ lưu lại giá trị đó và tại một thời điểm thì chỉ lưu một giá trị.

Ví dụ 1:
let a = 1;
//Tạo ra biến a và lưu giá trị của a vào ô nhớ - 1 let b = a;
//Tạo ra biến b, sao chép giá trị của biến a và lưu vào ô nhớ mới - 1 a = 2;
//Sửa giá trị của biến a và cập nhật lại ô nhớ - 2 console.log(b) //1

Như vậy, giá trị của a và b lưu ở hai ô nhớ khác nhau nên việc sửa ở ô nhớ này sẽ không ảnh hưởng đến ô nhớ khác.

Kiểu tham chiếu (Reference Types)

Kiểu này thì phức tạp hơn kiểu tham trị và được dùng cho các kiểu dữ liệu phức tạp: Object, Array, Function. Ở đây khi gán cho nó một giá trị thì nó không lưu lại giá trị này mà thực chất nó lưu lại địa chỉ của ô nhớ lưu giá trị này.

Ví dụ 2:
let a = { name: "cat" }
//Tạo ra biến a, lưu giá trị của a vào ô nhớ và gán lại địa chỉ ô nhớ cho biến a (a = #a001) let b = a
//Tạo ra biến b và gán giá trị của biến a cho b, ở đây chính là địa chỉ địa chỉ ô nhớ của a (b =#a001) a.name = "dog"
//Sửa giá trị của biến a thì giá trị trong ô nhớ được cập nhật console.log(b) // { name: "dog" }

Như vậy, a và b cùng lưu lại địa chỉ của một ô nhớ, khi một biến thay đổi thì giá trị trong ô nhớ thay đổi mà địa chỉ ô nhớ không thay đổi nên bất kỳ biến nào trỏ đến địa chỉ này đều bị thay đổi theo.

Ví dụ 3: const a = { id: 1, info: { name: "John", age: 23 }
}

Trong ví dụ trên ta thấy có hai object lồng nhau và cứ là object thì sẽ lưu theo kiểu tham chiếu. Đầu tiên, đi từ trong ra ngoài info sẽ được lưu vào ô nhớ và được gán cho một địa chỉ (info: #a001) sau đó a sẽ được lưu vào ô nhớ với giá trị { id: 1, info: #a001 } và gán lại địa chỉ của ô nhớ đó (a = #a002). Vậy nếu ta gán info cho một biến khác và thay đổi nó thì sẽ như thế nào?

const Info = a.info
Info.name = "David"
console.log(a.info.name)//"David"

Qua ví dụ này ta thấy một điều khá lạ là Info là hằng số tại sao lại có thể thay đổi được? Thực chất ở đây không phải là đang sửa giá trị của biến Info mà là sửa giá trị trong ô nhớ của nó còn nếu ta gán Info = b thì sẽ lỗi ngay bởi việc gán này sẽ làm thay đổi giá trị của nó.

Truyền tham số dạng tham trị và tham chiếu

Khi truyền tham số dạng tham trị vào trong một hàm thì thực chất trong hàm sẽ tạo ra một biến rồi gán bằng tham số truyền vào và cũng do tính chất của tham trị nên trong hàm có thay đổi thế nào thì giá trị truyền vào bên ngoài cũng không ảnh hưởng.

Ví dụ 4: Truyền tham số dạng tham trị
function changeNumber(a){ //let a = b a = 0; console.log(a);//0
} const b = 1;
changeNumber(b);
console.log(b)//1

Còn đối với kiểu tham chiếu, do tính chất của nó thì việc gán chỉ là gán địa chỉ ô nhớ lưu trữ giá trị nên việc thay đổi giá trị bên trong hàm vẫn sẽ ảnh hưởng đến giá trị bên ngoài.

Ví dụ 5: Truyền tham số dạng tham chiếu
function changeName(people){ people.name = "Hung"; console.log(people.name)//Hung
} const man = { name: "Thanh"}
changeName(man);
console.log(man.name)//Hung => Việc gán trong hàm là gán địa chỉ ô nhớ, khi thực hiện thay đổi thì giá trị của ô nhớ cũng thay đổi và man cùng chỉ đến ô nhớ đó nên khi hàm được chạy thì giá trị của man bên ngoài cũng được thay đổi theo.

Việc truyền tham số kiểu tham chiếu sẽ làm thay đổi giá trị của tham số truyền vào, vậy muốn bỏ tham chiếu thì phải làm như thế nào??? Tạo ra một object mới mà không làm ảnh hưởng đến object cũ thì ta có thể clone obj bằng spread operator, việc clone này sẽ tạo ra một object mới và lấy tất cả giá trị của object cũ vào object mới.

Vid dụ 6: const man1 = { name: "Sanji" }; //#a001
const man2 = { ...man1 }; #a002
//man2 là một object mới với địa chỉ mới và có tất cả giá trị của man1 man1.name = "Zoro"
console.log(man2.name)
//Do man2 và man1 trỏ đến hai ô nhớ khác nhau nên việc thay đổi man1 sẽ không làm thay đổi man2 nên man2.name vẫn là "Sanji".

Việc clone như vậy vẫn còn hạn chế đó là chỉ tạo ra ô nhớ mới cho cấp một của object còn nếu object có nhiều cấp lồng nhau thì không. Chính vì vậy để triệt để ta có thể sử dụng một cách khác đó là đó là chuyển object thành chuỗi rồi giải mã lại thành object, việc này sẽ tạo ra cả ô nhớ mới cho cả những object con. Nhưng việc mã hoá rồi giải mã này sẽ ảnh hưởng đến performance nếu như object quá lớn thì việc này sẽ mất thời gian. Vậy tuỳ hoàn cảnh mà ta sẽ chọn cách tối ưu nhất để sử dụng.

let b = JSON.parse(JSON.stringify(a));

Kết luận

Như vậy, kiểu tham trị thì lưu lại giá trị trong ô nhớ, ghi gán cho biến khác và sửa thì sẽ không làm thay đổi giá trị trước khi gán. Còn kiểu tham chiếu bản chất sẽ lưu lại địa chỉ ô nhớ chứa giá trị chứ không lưu giá trị, khi gán cho một biến khác thì sẽ gán địa chỉ này và khi sửa thì địa chỉ này không đổi nên các biến trỏ đến cùng địa chỉ này sẽ thay đổi khi có một cái nào đó thay đổi. Để tránh việc làm thay đổi giá trị kiểu tham chiếu thì ta clone ra một object mới rồi thay đổi hoặc chuyển object thành chuỗi rồi parse lại thành object để tạo ra object mới ở ô nhớ mới.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 500

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 374

- vừa được xem lúc

Đặt tên commit message sao cho "tình nghĩa anh em chắc chắn bền lâu"????

. Lời mở đầu. .

1 1 701

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 335

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 421

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 414