Nếu bạn đã học một số ngôn ngữ cấp thấp, chẳng hạn như C/C++, như tôi đã học ở trường đại học, bạn có thể đã biết rằng các biến có thể được truyền dưới dạng giá trị hoặc dưới dạng tham chiếu [và tất nhiên, dưới dạng con trỏ,
Trong khi trong C++, bạn cần xác định nó một cách rõ ràng, thì trong JavaScript, logic này được tích hợp sẵn. Đó là lý do tại sao không phải tất cả các nhà phát triển bắt đầu làm việc với JavaScript đều biết về sự khác biệt quan trọng này, điều này có thể dẫn đến rất nhiều lỗi không mong muốn.
Điều đầu tiên Trước tiên, hãy tìm hiểu ý nghĩa của nó
- Truyền theo giá trị có nghĩa là biến mới chỉ chấp nhận giá trị thực của biến ban đầu. Tôi. e. , các biến không phụ thuộc lẫn nhau và sự thay đổi của biến này sẽ không ảnh hưởng đến biến khác
- Chuyển qua tham chiếu có nghĩa là biến mới sử dụng địa chỉ bộ nhớ của biến ban đầu. Vì cả hai biến đều tham chiếu đến cùng một địa chỉ bộ nhớ, nên những thay đổi trong một biến sẽ ảnh hưởng đến một biến khác
Tôi yêu táo 🍎 🍏
Trong JavaScript, tất cả các kiểu dữ liệu nguyên thủy [Chuỗi, Số, Boolean] được truyền theo giá trị và các kiểu dữ liệu phức tạp như Mảng và Đối tượng được truyền theo tham chiếu
Bây giờ chúng ta sẽ điều tra nó bằng một số ví dụ đơn giản
Ở đây chúng tôi khởi tạo biến bar
bằng một biến foo
khác. Vì các kiểu dữ liệu nguyên thủy [Chuỗi, trong trường hợp của chúng tôi] được truyền theo giá trị, nên những thay đổi trong biến mới không ảnh hưởng đến biến ban đầu
Nó hoạt động theo cách tương tự khi chuyển các biến vào các đối số của hàm
Nhưng khi chúng ta cố gắng chuyển một biến phức tạp [e. g. Object], nó sẽ hoạt động hoàn toàn khác
Dưới đây chúng ta có thể thấy rằng khi chúng ta truyền một đối tượng cho một biến hoặc hàm khác, nó được truyền dưới dạng tham chiếu và những thay đổi trong một biến sẽ ảnh hưởng đến tất cả các biến khác tham chiếu đến cùng một địa chỉ bộ nhớ
Nhưng làm thế nào chúng ta có thể vượt qua hành vi mặc định?
JavaScript không cho phép chọn rõ ràng cách chuyển một biến, vì vậy chúng ta cần thực hiện các giải pháp thay thế để thay đổi hành vi mặc định
Truyền các biến nguyên thủy làm tham chiếu
Tôi không tìm thấy cách nào khác để chuyển các biến nguyên thủy làm tham chiếu ngoại trừ gói chúng vào một đối tượng hoặc một mảng rồi phá hủy nó
Nhưng nó không có ý nghĩa gì về mặt hiệu suất vì chúng ta cần tạo và hủy cấu trúc một biến phức tạp
Nếu bạn tìm thấy một giải pháp tốt hơn, xin vui lòng chia sẻ nó với chúng tôi
Truyền các biến phức tạp dưới dạng giá trị
Để chuyển một biến phức tạp thành một giá trị, chúng ta chỉ cần tạo bản sao của nó. Có nhiều cách để làm điều đó
Đối với các đối tượng
Object.create[]
— Tạo đối tượng mới bằng đối tượng hiện cóObject.assign[]
— Sao chép tất cả thuộc tính từ đối tượng nguồn sang đối tượng đích và trả về đối tượng kết quảObject.entries[]
+Object.fromEntries[]
— Phương thứcentries
chuyển đổi một đối tượng thành một mảng gồm các cặp [key, value] và phương thứcfromEntries
chuyển đổi nó trở lại thành một đối tượng mới- Toán tử trải rộng — Tạo một bản sao của một đối tượng
Đối với mảng
Array.map[]
— Tạo một bản sao với các sửa đổi được xác định [hoặc không có chúng]Array.slice[]
— Tạo một bản sao của một phần của mảng [hoặc toàn bộ mảng nếu được gọi không có đối số]foo
0 — Tạo một bản sao của một mảng- Toán tử trải rộng — Tạo một bản sao của một mảng
Tôi phải cảnh báo bạn rằng tất cả các phương thức này đều có một chi tiết quan trọng — chúng chỉ tạo ra một bản sao nông của một biến ban đầu. Điều đó có nghĩa là nếu bên trong mảng hoặc đối tượng của bạn, bạn có các biến phức tạp được lồng vào nhau, chúng sẽ vẫn được sao chép theo tham chiếu
Chỉ có một số cách để tạo bản sao sâu
foo
1+foo
2 — Phương thứcfoo
3 biến một biến thành một chuỗi và phương thứcfoo
4 sau đó biến một chuỗi trở lại một biến- Tạo phương pháp của riêng bạn để sao chép sâu hoặc sử dụng phương pháp thư viện. e. g.
foo
5
Phần kết luận
Và thông báo quan trọng cuối cùng. Hãy cẩn thận khi bạn sử dụng các phương thức tích hợp sẵn hoặc thư viện hoạt động với mảng và đối tượng, luôn kiểm tra xem chúng có thay đổi biến ban đầu hay tạo ra biến mới không
E. g. phương thức foo
6 sẽ xóa phần tử cuối cùng khỏi mảng ban đầu, trong khi phương thức foo
7 sẽ tạo phần tử mới