2013-01-23 32 views
22

Tôi đã đọc nhiều câu trả lời ở đây liên quan đến 'theo giá trị' và 'theo tham chiếu' để gửi mảng tới hàm javascript. Tuy nhiên tôi có một vấn đề gửi một mảng đến một chức năng và để lại mảng ban đầu không thay đổi gì. Ví dụ này sẽ giải quyết vấn đề:Mảng truy cập Javascript cho hàm theo giá trị, để mảng gốc không bị thay đổi

function myFunction(someArray) 
{ 
// any function that makes an array based on a passed array; 
// someArray has two dimensions; 
// I've tried copying the passed array to a new array like this (I've also used 'someArray' directly in the code); 

funcArray = new Array(); 
funcArray = someArray; 

var i = 0; 

    for(i=0; i<funcArray.length; i++) 
    { 
    funcArray[i].reverse; 
    } 

return funcArray; 

} 

Tôi không thể hiểu tại sao mọi thứ trong hàm này phải thay đổi mảng ban đầu.

gọi chức năng này trực tiếp làm thay đổi mảng ban đầu nếu cuộc gọi chức năng được gán cho một mảng mới:

myArray = [["A","B","C"],["D","E","F"],["G","H","I"]]; 
anotherArray = new Array(); 

anotherArray = myFunction(myArray); 
// myArray gets modified!; 

tôi đã cố gắng sử dụng .valueOf() để gửi nguyên thủy:

anotherArray = myFunction(myArray.valueOf()); 
// myArray gets modified!; 

tôi thậm chí đã cố gắng phá vỡ phần tử mảng xuống bởi phần tử và phần tử con theo phần tử con và gán tất cả cho một mảng 2-d mới và mảng ban đầu vẫn được sửa đổi.

Tôi cũng đã tham gia các phần tử con vào một chuỗi, xử lý chúng, chia chúng thành mảng và mảng ban đầu vẫn được sửa đổi.

Xin vui lòng, không ai biết làm thế nào tôi có thể vượt qua các giá trị mảng cho một hàm và không có thay đổi mảng đã qua?

+0

Xin lỗi, tôi quên đề cập rằng phương pháp cắt lát cũng không tạo ra sự khác biệt nào. Tôi đã nhìn thấy điều này đã đề cập và thử nó nhưng nó không ngăn chặn sự thay đổi mảng ban đầu (không .valueOf() được cho là để giảm nội dung mảng thành nguyên thủy) –

+0

Bây giờ tôi đã khám phá ý tưởng slice() một số chi tiết và vấn đề nằm trong nó là một mảng 2-d. Nếu tôi cắt mảng bên ngoài, nó sẽ không có sự khác biệt, mảng ban đầu vẫn bị thay đổi. Tuy nhiên, nếu tôi cắt từng mảng phụ, nó hoạt động! Tôi thiết lập một vòng lặp cho mỗi phần tử bên ngoài và gán slice của nó cho phần tử bên ngoài của một mảng mới. –

Trả lời

32

Bên trong hàm của bạn có này:

funcArray = new Array(); 
funcArray = someArray; 

này sẽ không thực sự sao chép someArray nhưng thay vì tham chiếu đến nó, đó là lý do các mảng gốc được sửa đổi.

Bạn có thể sử dụng Array.slice() để tạo bản sao được gọi là bản sao nông.

var funcArray = someArray.slice(0); 

Mảng ban đầu sẽ còn nguyên, nhưng mỗi phần tử của nó vẫn sẽ tham khảo mục tương ứng của họ trong mảng ban đầu. Đối với "nhân bản sâu", bạn cần phải thực hiện điều này một cách đệ quy; cách hiệu quả nhất được thảo luận trong những câu dưới đây:

What is the most efficient way to deep clone an object in JavaScript?

Btw, tôi đã thêm var trước funcArray. Làm như vậy làm cho nó cục bộ cho hàm thay vì là một biến toàn cầu.

+0

Cảm ơn, theo nhận xét thứ hai của tôi, slice() làm cho nó hoạt động nhưng chỉ khi áp dụng cho mỗi phần tử bên ngoài của mảng 2-d bằng cách lặp. –

1

Biến chỉ vào một mảng là tham chiếu đến mảng đó. Khi bạn vượt qua một mảng, bạn đang sao chép tham chiếu này.

Bạn có thể tạo bản sao nông với slice(). Nếu bạn muốn có một bản sao đầy đủ, sau đó recurse trong các đối tượng phụ, hãy ghi nhớ các caveats khi sao chép một số đối tượng.

+0

Cảm ơn, vâng, tôi đã tìm thấy nếu tôi cắt từng phần tử bên ngoài lần lượt nó hiện hoạt động. –

0

Một giải pháp chung chung sẽ là ...

// Use the JSON parse to clone the data. 
function cloneData(data) { 
    // Convert the data into a string first 
    var jsonString = JSON.stringify(data); 

    // Parse the string to create a new instance of the data 
    return JSON.parse(jsonString); 
} 

// An array with data 
var original = [1, 2, 3, 4]; 

function mutate(data) { 
    // This function changes a value in the array 
    data[2] = 4; 
} 

// Mutate clone 
mutate(cloneData(original)); 

// Mutate original 
mutate(original); 

này hoạt động cho các đối tượng cũng như mảng.

Rất hiệu quả khi bạn cần nhân bản sâu hoặc bạn không biết loại đó là gì.

sâu nhân bản ví dụ ...

var arrayWithObjects = [ { id: 1 }, { id: 2 }, { id: 3 } ]; 

function mutate(data) { 
    // In this case a property of an object is changed! 
    data[1].id = 4; 
} 

// Mutates a (DEEP) cloned version of the array 
mutate(cloneData(arrayWithObjects)); 

console.log(arrayWithObjects[1].id) // ==> 2 

Warnings

  • Sử dụng phân tích cú pháp JSON clone không phải là lựa chọn performant nhất!

  • Nó không sao chép chức năng chỉ hỗ trợ JSON kiểu dữ liệu

  • Không thể sao chép tài liệu tham khảo tròn

+0

Điều này có vẻ toàn diện nhưng tôi không quen thuộc với json. Có vẻ như tôi nên đầu tư vào việc tìm hiểu thêm. Vấn đề bây giờ được giải quyết bằng cách lặp từng phần tử bên ngoài và gán giá trị .slice() của nó cho một mảng mới. –

+0

Trong ví dụ của bạn, không nên 'cloneData' chỉ là' clone' (hoặc cách khác xung quanh)? – neemzy

+0

@neemzy Chính xác! Đã thay đổi nó. –

7

Tạo một bản sao của mảng mà bạn có thể sử dụng.

Một cách đơn giản để làm điều này là sử dụng var clone = original.slice(0);

+0

Cảm ơn. Tôi tìm thấy slice chỉ hoạt động khi được áp dụng cho từng phần tử bên ngoài bằng cách lặp: newArray [i] = mảng [i] .slice() –

0

Nếu bạn cần phải làm điều này với một đối tượng, cố gắng lừa ưa thích này ...

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT)); 
-1
var aArray = [0.0, 1.0, 2.0]; 
var aArrayCopy = aArray.concat(); 
aArrayCopy[0] = "A changed value."; 
console.log("aArray: "+aArray[0]+", "+aArray[1]+", "+aArray[2]); 
console.log("aArrayCopy: "+aArrayCopy[0]+", "+aArrayCopy[1]+", "+aArrayCopy[2]); 

Câu trả lời này đã được chỉnh sửa . Ban đầu tôi đưa ra rằng các nhà điều hành new xử lý các giải pháp, nhưng ngay sau đó nhận ra rằng lỗi. Thay vào đó, tôi đã chọn sử dụng phương thức concat() để tạo một bản sao. Câu trả lời ban đầu đã không hiển thị toàn bộ mảng, vì vậy lỗi đã vô tình bị che khuất. Đầu ra mới được hiển thị bên dưới sẽ chứng minh rằng câu trả lời này hoạt động như mong đợi.

aArray: 0, 1, 2 
aArrayCopy: A changed value., 1, 2 
+0

Mã đó không làm những gì bạn nghĩ, với 'mảng mới' (aArray) 'bạn tạo mới mảng trong đó phần tử đầu tiên là 'aArray', không tạo bản sao của mảng ban đầu, ghi lại toàn bộ mảng thay vì phần tử đầu tiên và bạn sẽ thấy sự khác biệt. –

+0

Cảm ơn Alberto. Bạn đã nhanh chóng trả lời và sửa lại. Sử dụng 'new Array (someArray);' sẽ thiết lập độ dài là 1 và thiết lập phần tử đầu tiên đó là tham chiếu của mảng đã truyền mà không gán một giá trị đúng cho mỗi phần tử như mong đợi cho một giá trị truyền theo giá trị. Gần đây tôi đã sử dụng Float32Array, và phải học lại rằng mảng cơ bản không xây dựng cùng một cách. Sản lượng mẫu thử của tôi không xác định được lỗi. Bây giờ nó kết quả chính xác toàn bộ bản sao mảng. –

Các vấn đề liên quan