Hai xu của tôi ... Đây là cách tôi hiểu nó. (Hãy sửa tôi nếu tôi sai)
Đã đến lúc bỏ đi tất cả những gì bạn biết về việc vượt qua giá trị / tham chiếu.
Bởi vì trong JavaScript, nó không quan trọng cho dù nó được truyền theo giá trị hay bằng tham chiếu hay bất cứ điều gì. Vấn đề là đột biến so với việc gán các tham số được truyền vào một hàm.
OK, hãy để tôi làm hết sức mình để giải thích những gì tôi muốn nói. Giả sử bạn có một vài đối tượng.
var object1 = {};
var object2 = {};
Những gì chúng ta đã làm là "gán" ... Chúng ta đã gán 2 đối tượng trống riêng biệt cho các biến "object1" và "object2".
Bây giờ, hãy nói rằng chúng tôi thích object1 hơn ... Vì vậy, chúng tôi "gán" một biến mới.
var favoriteObject = object1;
Tiếp theo, vì bất kỳ lý do gì, chúng tôi quyết định rằng chúng tôi thích đối tượng 2 hơn. Vì vậy, chúng tôi chỉ đơn giản là làm một chút phân công lại.
favoriteObject = object2;
Không có gì xảy ra với object1 hoặc object2. Chúng tôi đã không thay đổi bất kỳ dữ liệu nào cả. Tất cả những gì chúng tôi đã làm là gán lại những gì đối tượng yêu thích của chúng tôi. Điều quan trọng là phải biết rằng cả object2 và FavoritesObject đều được gán cho cùng một đối tượng. Chúng ta có thể thay đổi đối tượng đó thông qua một trong hai biến đó.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
OK, bây giờ chúng ta hãy xem các nguyên thủy như chuỗi chẳng hạn
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Một lần nữa, chúng tôi chọn một yêu thích.
var favoriteString = string1;
Cả hai biến yêu thíchString và string1 của chúng tôi đều được gán cho 'Hello world'. Bây giờ, nếu chúng ta muốn thay đổi yêu thích của chúng ta thì sao ??? Chuyện gì sẽ xảy ra???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Uh oh .... chuyện gì đã xảy ra Chúng tôi không thể thay đổi chuỗi1 bằng cách thay đổi FavoritesString ... Tại sao ?? Bởi vì chúng tôi đã không thay đổi đối tượng chuỗi của chúng tôi . Tất cả những gì chúng tôi đã làm là "TÁI TẠO" biến yêu thíchString thành một chuỗi mới. Điều này về cơ bản ngắt kết nối nó khỏi chuỗi1. Trong ví dụ trước, khi chúng tôi đổi tên đối tượng của mình, chúng tôi đã không chỉ định bất cứ điều gì. (Chà, không phải cho chính biến , ... tuy nhiên, chúng tôi đã gán thuộc tính name cho một chuỗi mới.) Thay vào đó, chúng tôi chỉ đơn giản là biến đổi đối tượng giữ các kết nối giữa 2 biến và các đối tượng bên dưới. (Ngay cả khi chúng ta đã muốn sửa đổi hoặc đột biến đối tượng chuỗi bản thân, chúng tôi không thể có, bởi vì các chuỗi thực sự bất biến trong JavaScript.)
Bây giờ, chuyển sang các hàm và truyền tham số .... Khi bạn gọi hàm và truyền tham số, về cơ bản, việc bạn đang làm là "gán" cho một biến mới và nó hoạt động chính xác như khi bạn chỉ định sử dụng dấu bằng (=).
Lấy những ví dụ này.
var myString = 'hello';
// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment
console.log(myString); // Logs 'hello'
console.log(param1); // Logs 'world'
Bây giờ, điều tương tự, nhưng với một chức năng
function myFunc(param1) {
param1 = 'world';
console.log(param1); // Logs 'world'
}
var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);
console.log(myString); // logs 'hello'
OK, bây giờ chúng ta hãy đưa ra một vài ví dụ sử dụng các đối tượng thay vì ... trước tiên, không có chức năng.
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;
// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'
// Now, let's reassign the variable
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';
Bây giờ, điều tương tự, nhưng với một cuộc gọi chức năng
function myFunc(otherObj) {
// Let's mutate our object
otherObj.firstName = 'Sue';
console.log(otherObj.firstName); // Logs 'Sue'
// Now let's re-assign
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
console.log(otherObj.firstName); // Logs 'Jack'
// Again, otherObj and myObject are assigned to 2 very different objects
// And mutating one object doesn't magically mutate the other
}
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);
console.log(myObject.firstName); // Logs 'Sue', just like before
OK, nếu bạn đọc qua toàn bộ bài đăng này, có lẽ bây giờ bạn đã hiểu rõ hơn về cách các hàm gọi hoạt động trong JavaScript. Không có vấn đề gì nếu một cái gì đó được thông qua bởi tham chiếu hoặc theo giá trị ... Vấn đề là sự phân công so với đột biến.
Mỗi khi bạn chuyển một biến cho một hàm, bạn sẽ "Gán" cho dù tên của biến tham số là gì, giống như nếu bạn sử dụng dấu bằng (=).
Luôn nhớ rằng dấu bằng (=) có nghĩa là gán. Luôn nhớ rằng việc truyền tham số cho hàm trong JavaScript cũng có nghĩa là gán. Chúng giống nhau và 2 biến được kết nối theo cùng một cách chính xác (nghĩa là chúng không có, trừ khi bạn tính rằng chúng được gán cho cùng một đối tượng).
Lần duy nhất "sửa đổi một biến" ảnh hưởng đến một biến khác là khi đối tượng cơ bản bị đột biến (trong trường hợp đó bạn không sửa đổi biến, nhưng chính đối tượng đó.
Không có điểm nào trong việc phân biệt giữa các đối tượng và nguyên thủy, bởi vì nó hoạt động theo cùng một cách chính xác như thể bạn không có chức năng và chỉ sử dụng dấu bằng để gán cho một biến mới.
Gotcha duy nhất là khi tên của biến bạn truyền vào hàm giống với tên của tham số hàm. Khi điều này xảy ra, bạn phải xử lý tham số bên trong hàm như thể nó là một biến hoàn toàn mới riêng tư đối với hàm (vì nó là)
function myFunc(myString) {
// myString is private and does not affect the outer variable
myString = 'hello';
}
var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';
myFunc(myString);
console.log(myString); // Logs 'test'