Hướng dẫn javascript are arrays passed by reference or value - javascript là các mảng được truyền bởi tham chiếu hoặc giá trị

Trong bài đăng này, chúng tôi sẽ xem xét vượt qua giá trị và vượt qua tham chiếu trong JavaScript.

Hãy cùng xem những gì được truyền qua giá trị và vượt qua tham chiếu trước khi xem xét bối cảnh JavaScript của nó.

Vượt qua giá trị:

Trong Pass by giá trị, hàm được gọi bằng cách truyền trực tiếp giá trị của biến làm đối số. Thay đổi đối số bên trong hàm không ảnh hưởng đến biến được truyền từ bên ngoài hàm.

JavaScript luôn vượt qua giá trị để thay đổi giá trị của biến không bao giờ thay đổi nguyên thủy cơ bản (chuỗi hoặc số). so changing the value of the variable never changes the underlying primitive (String or number).

function callByValue(varOne, varTwo) { 
console.log("Inside Call by Value Method");
varOne = 100;
varTwo = 200;
console.log("varOne =" + varOne +"varTwo =" +varTwo);
}
let varOne = 10;
let varTwo = 20;
console.log("Before Call by Value Method");
console.log("varOne =" + varOne +"varTwo =" +varTwo);
callByValue(varOne, varTwo) console.log("After Call by Value Method");
console.log("varOne =" + varOne +"varTwo =" +varTwo);

output will be :
---------------
Before Call by Value Method
varOne =10 varTwo =20
Inside Call by Value Method
varOne =100 varTwo =200
After Call by Value Method
varOne =10 varTwo =20

Tuy nhiên, khi một biến đề cập đến một đối tượng bao gồm mảng, giá trị là tham chiếu đến đối tượng.

Vượt qua tham chiếu:

Trong tham chiếu vượt qua, hàm được gọi bằng cách truyền trực tiếp tham chiếu/địa chỉ của biến làm đối số. Thay đổi đối số bên trong hàm ảnh hưởng đến biến được truyền từ bên ngoài hàm. Trong các đối tượng và mảng JavaScript theo sau vượt qua tham chiếu.

function callByReference(varObj) { 
console.log("Inside Call by Reference Method");
varObj.a = 100;
console.log(varObj);
}
let varObj = {a:1};
console.log("Before Call by Reference Method");
console.log(varObj);
callByReference(varObj) console.log("After Call by Reference Method");
console.log(varObj);
output will be :
---------------
Before Call by Reference Method
{a: 1}
Inside Call by Reference Method
{a: 100}
After Call by Reference Method
{a: 100}

Vì vậy, nếu chúng ta chuyển đối tượng hoặc mảng làm đối số cho phương thức, thì có khả năng giá trị của đối tượng có thể thay đổi.

Nếu bạn muốn tạo trang web hoặc cổng thông tin - liên hệ với chúng tôi @ https://www.bondesk.in

Ngôn ngữ lập trình đầu tiên tôi học được là C ++ và khi học nó, tôi đã học được về các giá trị và tham chiếu qua từng giá trị; C ++ sử dụng giá trị qua từng giá trị theo mặc định để chuyển các đối số vào các chức năng. Bạn có thể chỉ định rằng bạn muốn chuyển qua từng tham chiếu, tuy nhiên bằng cách đặt một ký tự ampers và giữa kiểu dữ liệu và tên tham số trong danh sách tham số trong định nghĩa chức năng. Tuy nhiên, JavaScript không cung cấp cho bạn các tùy chọn như vậy, nó có một quy tắc để mang lại tất cả và trong bóng tối ràng buộc chúng (đối số với các tham số, không phải là sinh vật của Trung Quốc với Chúa tể bóng tối). Làm việc trên một ứng dụng ngày hôm nay, tôi đã gặp phải một vấn đề liên quan đến điều này mặc dù vậy, vì vậy, hãy để Lôi làm sáng tỏ bóng tối đó của những gì JavaScript làm đằng sau hậu trường khi chuyển các đối số vào một chức năng.

Kỉ niệm

Trước hết, hãy kiểm tra bộ nhớ nhanh và đưa ra sự khác biệt giữa các giá trị qua từng giá trị và chuyển qua. Các biến giữ dữ liệu trong bộ nhớ, nhưng một biến thực sự chỉ là một con trỏ đến một vị trí trong bộ nhớ. Bằng cách tạo một biến, bạn chỉ nói với chương trình của mình để chọn một khoảng trống trong bộ nhớ máy tính và nhớ nó để bạn có thể gán một giá trị cho nó và lấy giá trị đó khi bạn muốn.

Phần tham chiếu của các tham chiếu tham chiếu đề cập đến các vị trí bộ nhớ trong khi giá trị ‘trong các giá trị vượt qua đề cập đến giá trị thực tế ở vị trí bộ nhớ. Vì vậy, khi bạn sử dụng từng giá trị có nghĩa là bất kỳ đối số nào bạn chuyển đến một hàm chỉ có các giá trị của chúng được sao chép và chuyển sang các tham số bên trong định nghĩa hàm. Điều này có nghĩa là các tham số bên trong hàm không giống như các biến bạn đã truyền dưới dạng đối số. Chúng có cùng các giá trị, nhưng các giá trị đó được tạo ở các vị trí bộ nhớ mới, vì vậy nếu bạn thay đổi giá trị của một trong các tham số đó trong hàm thay đổi không ảnh hưởng đến biến bên ngoài hàm. Không có kết nối giữa đối số bên ngoài hàm và tham số bên trong hàm vì tất cả những gì bạn đã làm là vượt qua các giá trị, do đó qua giá trị.

// A pseudo-code example of pass-by-valuefunction funky(number) {
number = 7;
}
num = 5;
funky(num);
print num; // 5

Trong ví dụ trên, num biến vẫn bằng 5 mặc dù hàm FUNKY đã thay đổi nó thành 7 vì vị trí bộ nhớ mà Num trỏ đến Wasn được truyền vào hàm, chỉ có giá trị của nó, 5, đã được truyền. Vì vậy, Num không bị ảnh hưởng. Số tham số được tạo bởi hàm để trỏ đến một vị trí mới trong bộ nhớ chứa giá trị 5 và sau đó được thay đổi thành 7.

By-Ty-tham chiếu có nghĩa là bạn đang truyền không phải là giá trị của biến mà là vị trí bộ nhớ thực của biến. Bạn đang chuyển tham chiếu đến giá trị. Vì vậy, trong ví dụ tiếp theo này về tham chiếu qua từng lần, vị trí bộ nhớ cho NUM được chuyển vào hàm để số đó là một tham chiếu đến cùng một vị trí bộ nhớ. Rõ ràng điều này có nghĩa là bất cứ điều gì bạn làm với số cũng sẽ ảnh hưởng đến Num.

// A pseudo-code example of pass-by-referencefunction funky(number) {
number = 7;
}
num = 5;
funky(num);
print num; // 7

JavaScript từ Pass-By Rules

JavaScript tuân theo một quy tắc khi chuyển các đối số vào các chức năng, đó là có các quy tắc khác nhau!

JavaScript luôn sử dụng giá trị qua từng giá trị, tuy nhiên khi loại dữ liệu của đối số không phải là loại nguyên thủy thì giá trị được truyền thực sự là vị trí bộ nhớ. Vì vậy, năm loại nguyên thủy (chuỗi, số, booleans, null và không xác định) là có giá trị như bạn mong đợi. Nhưng bất kỳ loại loại dữ liệu phức tạp nào (đối tượng và mảng) đều có giá trị chuyển qua với tài liệu tham khảo của chúng là giá trị nên có hiệu lực, chúng được tham chiếu theo từng lần.

Ví dụ về cách JavaScript hành xử với các đối số nguyên thủy:

// primitive values are pass-by-valuefunction funky(number) {
number+= 7;
}
let num = 5;
funky(num);
console.log(num); // 5

Ví dụ về cách JavaScript hành xử với các đối số không định hướng:

// non-primitive values are pass-by-referencefunction funky(arr, obj) {
arr.push(4);
obj.food = 'apple pie';
}
let myArr = [1,2,3];
let myObj = { name: 'Tony', food: 'pizza' };
funky(myArr, myObj);console.log(myArr); // [1,2,3,4]
console.log(myObj); // { name: 'Tony', food: 'apple pie' }

Trong ví dụ trên, bạn có thể thấy một đối tượng và một mảng được chuyển qua từng tham chiếu vì các biến bên ngoài Myarr và MYOBJ được thay đổi bên trong hàm. Điều này là do các vị trí bộ nhớ của Myarr và MYOBJ được chuyển vào hàm thay vì các giá trị mảng và đối tượng của chúng.

By-By-Reference là tốt vì điều đó có nghĩa là nếu bạn đang thao túng nhiều mảng hoặc đối tượng trong một chức năng mà bạn không cần phải trả lại nhiều thứ. Tuy nhiên, nếu bạn thực hành một cách lập trình chức năng hiệu ứng không bên thì điều này sẽ rất tệ vì chức năng của bạn, bằng cách thao tác các giá trị bên ngoài, đang thay đổi trạng thái bên ngoài của ứng dụng giá trị trả về của nó). Dù sao, đó là một cuộc thảo luận cho một thời gian khác.

Thủ thuật của bộ nhớ

Tuy nhiên, điều này không có nghĩa là bạn có thể làm bất cứ điều gì bạn muốn đối tượng hoặc mảng và vẫn có những thay đổi của nó ảnh hưởng đến biến truyền ban đầu. Lý do là vị trí bộ nhớ. Nếu bạn thao tác các phần tử hoặc thuộc tính riêng lẻ của một mảng hoặc đối tượng thì tham chiếu đến biến đó không thay đổi, do đó, kết nối giữa đối số và tham số vẫn còn nguyên vì cả hai vẫn chỉ vào cùng một vị trí trong bộ nhớ.

Trong JavaScript bất cứ khi nào bạn gán một giá trị mới cho một biến, những gì xảy ra là một vị trí bộ nhớ mới được gán cho biến đó với giá trị đã cho tại vị trí đó trong bộ nhớ. Vì vậy, việc gán một mảng hoàn toàn mới cho một tham số mảng trong một hàm làm cho tham số đó trỏ đến một vị trí bộ nhớ mới, trong khi biến mảng gốc bên ngoài hàm vẫn trỏ đến vị trí bộ nhớ gốc. Điều tương tự nếu bạn gán một đối tượng mới theo nghĩa đen cho một tham số đối tượng trong một hàm. Điều này có nghĩa là liên kết (vị trí bộ nhớ chia sẻ) giữa đối số bên ngoài và tham số bên trong bị phá vỡ để các thay đổi bên trong hàm sẽ không ảnh hưởng đến các đối số bên ngoài hàm.

Ví dụ mã cuối cùng giữ nguyên các tham chiếu vì hàm trực tiếp thao tác với mảng và đối tượng bằng cách sử dụng phương thức đẩy mảng mảng để thêm phần tử và thay đổi trực tiếp một giá trị trên một thuộc tính của đối tượng. Chức năng đã tạo ra một mảng hoặc đối tượng mới, nó chỉ thay đổi các phần của chúng - nó đã thay đổi các giá trị phần tử/thuộc tính của chúng, không phải các tài liệu tham khảo mảng/đối tượng.

Tuy nhiên, trong ví dụ dưới đây, tôi sẽ chỉ ra cách bạn có thể phá vỡ liên kết tham chiếu giữa đối số bên ngoài và tham số bên trong bằng cách gán một giá trị hoàn toàn mới cho tham số.

// example changing memory locations, thereby breaking reference linkfunction funky(arr, obj) {
arr = [-1,-2,-3];
obj = { age: 12 };
console.log(arr); // [-1,-2,-3]
console.log(obj); // { age: 12 }
}
let myArr = [1,2,3];
let myObj = { name: 'Tony', food: 'pizza' };
funky(myArr, myObj);console.log(myArr); // [1,2,3]
console.log(myObj); // { name: 'Tony', food: 'pizza' }

Trong ví dụ trên khi [-1, -2, -3] được gán cho tham số mảng, điều xảy ra là JavaScript tạo một vị trí bộ nhớ mới cho [-1, -2, -3] và gán vị trí bộ nhớ đó cho ARR. Các vị trí bộ nhớ cho ARR và Myarr bây giờ khác nhau nên ARR không còn ảnh hưởng đến Myarr. Điều tương tự đã xảy ra giữa Obj và Myobj.

Vấn đề của tôi

Lý do tôi đã viết bài viết này là vì tôi gặp phải một vấn đề hôm nay trong ứng dụng mà tôi đang làm việc ở nơi tôi mong đợi mảng tôi đã chuyển vào một chức năng sẽ được thay đổi dựa trên những gì tôi đã làm trong chức năng nhưng tôi nhận ra thật đáng buồn là nó không 't. Hãy để xem những gì tôi đang làm.

Tôi đã có một mảng ID người dùng và một mảng song song các tọa độ GPS của họ. Tôi muốn chuyển cả hai mảng vào hàm, cùng với khoảng cách tối đa và thêm một cặp tọa độ GPS, sau đó tìm ra khoảng cách giữa mỗi cặp tọa độ trong mảng và cặp tọa độ độc lập. Hàm sẽ lọc ra người dùng từ mảng người dùng ở xa hơn khoảng cách tối đa và tạo một mảng khoảng cách để phù hợp với người dùng còn lại trong mảng. Mảng khoảng cách mới này được trả về từ hàm và được gán cho một mảng bên ngoài hàm để biểu thị khoảng cách mà mỗi người dùng là từ cặp tọa độ độc lập.

Về cơ bản, tôi muốn lọc người dùng bằng khoảng cách tối đa và trả về một cặp khoảng cách phù hợp cho mỗi người dùng.

Điều quan trọng đối với chức năng này là thực tế là các mảng được truyền qua tham chiếu để mảng người dùng bên ngoài sẽ được lọc xuống bên trong hàm. Ngoại trừ tôi đã sử dụng phương thức bộ lọc mảng JavaScript, Array.prototype.filter, trả về một mảng hoàn toàn mới có tham chiếu đến vị trí bộ nhớ mới được phân bổ. Vì vậy, bên trong hàm khi tôi gán kết quả của bộ lọc cho tham số mảng người dùng được gán một vị trí bộ nhớ mới cho mảng, do đó mảng người dùng bên ngoài hàm và mảng người dùng bên trong hàm không còn trỏ đến cùng một vị trí bộ nhớ. Điều này có nghĩa là tôi đã thực sự nhận được mảng được lọc ra khỏi chức năng.

Dưới đây là một số mã cơ bản cho thấy vấn đề:

userArray;       // filled with user IDs
coordsArray; // filled with coordinates for each user from userArray
myCoords; // has pair of coordinates for this user in lat, lon properties
maxDist; // holds a number
let distArray = convertGpsToMiles(userArray, coordsArray, myCoords, maxDist);console.log(userArray); // still holds original userArray unfilteredfunction convertGpsToMiles(users, coords, myLocation, maxD) {
let miles;
let distances = [];
users = users.filter((el, index) => {
miles = convertCoordsToDistance(myLocation, coords[i].lat, coords[i].lon);
if (miles <= maxD) {
distances.push(miles);
return true;
} else {
return false;
}
});
return distances;
}

Người dùng bên ngoài và mảng người dùng chức năng của người dùng được tách ra khi tôi chỉ định mảng được lọc mới cho người dùng với người dùng.filter ().

Solution(s)

Trước khi tôi thực sự bắt đầu nghĩ về cách JavaScript hoạt động với bộ nhớ, tôi đã thử một vài bản sửa lỗi không hoạt động vì không ai trong số chúng có thể gán mảng được lọc mới từ Users.Filter () cho mảng người dùng trong hàm.

Một giải pháp trong JavaScript thuần túy sẽ là sử dụng một vòng lặp tiêu chuẩn thay vì phương thức mảng.prototype.filter. Trong vòng lặp, nếu Miles nhỏ hơn hoặc bằng MAXD, tôi sẽ đẩy dặm vào mảng khoảng cách và sau đó sử dụng phương thức JavaScript tựa Array.prototype.Splice để cắt bỏ người dùng không mong muốn. Bằng cách này, tôi sẽ trực tiếp thao tác với mảng người dùng thay vì gán một mảng mới cho người dùng, vì vậy tham chiếu đến vị trí bộ nhớ sẽ không thay đổi. Mặc dù do phương pháp mối nối thay đổi độ dài của mảng tại chỗ, tôi sẽ phải đảm bảo thao tác bộ đếm vòng để theo kịp các thay đổi được thực hiện theo chiều dài của mảng và điều này có nghĩa là tôi cũng cần phải SPLICE OUT các phần tử tại cùng một chỉ số trong mảng phối hợp để làm cho mảng các điều phối vẫn song song với mảng người dùng.

function convertGpsToMiles(users, coords, myLocation, maxD) {
let miles;
let distances = [];
for (let i=0; i < users.length; i++) {
miles = convertCoordsToDistance(myLocation, coords[i].lat, coords[i].lon);
if (miles <= maxD) {
distances.push(miles);
} else {
users.splice(i, 1);
coords.splice(i, 1);
i--;
}
}
return distances;
}

Điều này sẽ hoạt động và nhanh hơn so với sử dụng phương thức Array.prototype.filter, vì vậy nếu ứng dụng của tôi trở nên phổ biến và có hàng tấn người dùng đồng thời, tôi có thể cố gắng tối ưu hóa hiệu quả là sử dụng giải pháp này.

Vì tôi đang sử dụng góc, một giải pháp khác là sử dụng phương thức Angular.copy () với cú pháp sau: Angular.Copy (SRC, Dest)

Phương thức Angular.copy () thực hiện một bản sao sâu từ mảng nguồn sang mảng đích, có nghĩa là nó đi vào và sao chép các phần tử riêng lẻ của mảng để vị trí bộ nhớ không thay đổi, thay vì chỉ hướng mảng đích đến Vị trí bộ nhớ của mảng nguồn hoặc sao chép toàn bộ mảng nguồn (như những gì mảng.prototype.slice sẽ không làm không có đối số) và trỏ mảng đích đến vị trí bộ nhớ của bản sao mới.

Các tài liệu Angular mô tả chính xác những gì nó làm, nó xóa mảng đích và sau đó sao chép trên các phần tử riêng lẻ từ mảng nguồn:

* @ngdoc function
* @name angular.copy
* @module ng
* @kind function
*
* @description
* Creates a deep copy of `source`, which should be an object or an array.
*
* * If no destination is supplied, a copy of the object or array is created.
* * If a destination is provided, all of its elements (for arrays) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.

Vì tôi sử dụng góc, tôi đã đi với giải pháp góc và sử dụng Angular.copy (), chuyển trong mảng được lọc làm mảng nguồn và tham số mảng người dùng của tôi làm đích.

function callByReference(varObj) { 
console.log("Inside Call by Reference Method");
varObj.a = 100;
console.log(varObj);
}
let varObj = {a:1};
console.log("Before Call by Reference Method");
console.log(varObj);
callByReference(varObj) console.log("After Call by Reference Method");
console.log(varObj);
output will be :
---------------
Before Call by Reference Method
{a: 1}
Inside Call by Reference Method
{a: 100}
After Call by Reference Method
{a: 100}
0

Và nó hoạt động!

Sự kết luận

Vì vậy, bạn có nó, JavaScript chuyển các nguyên thủy theo giá trị nhưng về cơ bản chuyển các mảng và đối tượng bằng cách tham khảo. Nhưng bạn đã phải chú ý rằng bạn không chỉ định lại một đối tượng hoặc mảng bên trong một chức năng do đó làm cho nó tham chiếu một vị trí bộ nhớ mới và phá vỡ liên kết mà nó có với đối số ban đầu. Về cơ bản, nếu bạn sử dụng toán tử gán, =, với toàn bộ mảng hoặc toàn bộ đối tượng ở phía bên trái thì bạn đang gán một vị trí bộ nhớ hoàn toàn mới cho biến đó. Thay vào đó, nếu bạn cần lưu giữ các tham chiếu trong một hàm, bạn muốn trực tiếp thay đổi thuộc tính trên các đối tượng với toán tử DOT hoặc sử dụng các phương thức mảng thao túng một mảng tại chỗ (như splice (), push () so với những người trả về một mảng mới (như Filter (), map (), Slice (), v.v.).

Kịch bản hạnh phúc!

Mảng có phải là loại tham chiếu trong JavaScript không?

Đối tượng, mảng và chức năng là các loại tham chiếu.Một loại nguyên thủy có kích thước cố định trong bộ nhớ.. A primitive type has a fixed size in memory.

Các đối tượng JavaScript có được truyền bởi giá trị hay truyền qua tham chiếu không?

Trong mảng JavaScript và đối tượng theo sau bởi thuộc tính tham chiếu.Trong tham chiếu vượt qua, các tham số được truyền dưới dạng đối số không tạo ra bản sao của riêng mình, nó đề cập đến giá trị ban đầu để các thay đổi được thực hiện bên trong ảnh hưởng đến giá trị ban đầu.pass by reference property. In Pass by reference, parameters passed as an arguments does not create its own copy, it refers to the original value so changes made inside function affect the original value.

JavaScript có lưu trữ bằng cách tham chiếu hoặc giá trị không?

Trong JavaScript, bạn có thể chuyển qua giá trị và bằng cách tham khảo.Sự khác biệt chính giữa hai là chuyển qua giá trị xảy ra khi gán nguyên thủy trong khi truyền bằng cách tham chiếu khi gán các đối tượng.you can pass by value and by reference. The main difference between the two is that passing by value happens when assigning primitives while passing by reference when assigning objects.

Những loại dữ liệu nào được truyền bởi JavaScript tham chiếu?

Trong JavaScript, tất cả các loại dữ liệu nguyên thủy (chuỗi, số, boolean) được truyền bởi giá trị và các loại dữ liệu phức tạp như mảng và đối tượng được truyền qua tham chiếu.Array and Object are passed by reference .