Trong JavaScript, các kỹ thuật bản sao sâu phụ thuộc vào các yếu tố trong một mảng. Hãy bắt đầu ở đó.
Ba loại yếu tố
Các yếu tố có thể là: giá trị theo nghĩa đen, cấu trúc theo nghĩa đen hoặc nguyên mẫu.
// Literal values [type1]
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';
// Literal structures [type2]
const arrayLiteral = [];
const objectLiteral = {};
// Prototypes [type3]
const booleanPrototype = new Bool[true];
const numberPrototype = new Number[1];
const stringPrototype = new String['true'];
const arrayPrototype = new Array[];
const objectPrototype = new Object[]; // or `new function [] {}
Từ các yếu tố này, chúng ta có thể tạo ba loại mảng.
// 1] Array of literal-values [boolean, number, string]
const type1 = [ true, 1, "true" ];
// 2] Array of literal-structures [array, object]
const type2 = [ [], {} ];
// 3] Array of prototype-objects [function]
const type3 = [ function [] {}, function [] {} ];
Kỹ thuật sao chép sâu phụ thuộc vào ba loại mảng
Dựa trên các loại yếu tố trong mảng, chúng ta có thể sử dụng các kỹ thuật khác nhau để sao chép sâu.
Kỹ thuật sao chép sâu
Điểm chuẩn
//www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison
Mảng các giá trị theo nghĩa đen [Type1]
[ ...myArray ]
,myArray.splice[0]
,myArray.slice[]
vàmyArray.concat[]
có thể được sử dụng để sao chép các mảng sâu với các giá trị theo nghĩa đen [boolean, số và chuỗi]; Trong đóslice[]
có hiệu suất cao nhất trong Chrome và lan truyền
0 có hiệu suất cao nhất trong Firefox.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
The[ ...myArray ]
,myArray.splice[0]
,myArray.slice[]
, andmyArray.concat[]
techniques can be used to deep copy arrays with literal values [boolean, number, and string] only; whereslice[]
has the highest performance in Chrome, and spread
0 has the highest performance in Firefox.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
Mảng của các giá trị theo nghĩa đen [Type1] và cấu trúc theo nghĩa đen [Type2] Kỹ thuật
1 có thể được sử dụng để sao chép sâu các giá trị theo nghĩa đen [boolean, số, chuỗi] và cấu trúc theo nghĩa đen [mảng, đối tượng], nhưng không phải là đối tượng nguyên mẫu.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
The
1 technique can be used to deep copy literal values [boolean, number, string] and literal structures [array, object], but not prototype objects.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
Tất cả các mảng [Type1, type2, type3]
- Các kỹ thuật Lo-Dash
2 hoặc jQuery// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
3 có thể được sử dụng để kết hợp sâu tất cả các loại mảng. Trong đó kỹ thuật Lodash// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
4 có hiệu suất cao nhất.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
- Và đối với những người tránh các thư viện của bên thứ ba, chức năng tùy chỉnh bên dưới sẽ kết hợp sâu tất cả các loại mảng, với hiệu suất thấp hơn
4 và hiệu suất cao hơn so với// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
6.// 1] Array of literal-values [boolean, number, string] const type1 = [ true, 1, "true" ]; // 2] Array of literal-structures [array, object] const type2 = [ [], {} ]; // 3] Array of prototype-objects [function] const type3 = [ function [] {}, function [] {} ];
- Các kỹ thuật Lo-Dash
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
Vì vậy, để trả lời câu hỏi ...
Câu hỏi
var arr1 = ['a','b','c'];
var arr2 = arr1;
Tôi nhận ra rằng ARR2 đề cập đến cùng một mảng với ARR1, thay vì một mảng mới, độc lập. Làm thế nào tôi có thể sao chép mảng để có được hai mảng độc lập?
Câu trả lời
Vì
// 1] Array of literal-values [boolean, number, string]
const type1 = [ true, 1, "true" ];
// 2] Array of literal-structures [array, object]
const type2 = [ [], {} ];
// 3] Array of prototype-objects [function]
const type3 = [ function [] {}, function [] {} ];
7 là một loạt các giá trị theo nghĩa đen [boolean, số hoặc chuỗi], bạn có thể sử dụng bất kỳ kỹ thuật sao chép sâu nào được thảo luận ở trên, trong đó slice[]
và lây lan ____10 có hiệu suất cao nhất.arr2 = arr1.slice[];
arr2 = [...arr1];
arr2 = arr1.splice[0];
arr2 = arr1.concat[];
arr2 = JSON.parse[JSON.stringify[arr1]];
arr2 = copy[arr1]; // Custom function needed, and provided above
arr2 = _.cloneDeep[arr1]; // Lo-dash.js needed
arr2 = jQuery.extend[true, [], arr1]; // jQuery.js needed
Khi chúng ta cần sao chép một mảng, chúng ta thường sử dụng lát cắt. Nhưng với ES6, bạn cũng có thể sử dụng toán tử lây lan để nhân đôi một mảng. Khá tiện lợi, phải 🤩
# Tại sao tôi có thể sử dụng function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
0 để sao chép một mảng?
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
Bởi vì các mảng trong JS là các giá trị tham chiếu, vì vậy khi bạn cố gắng sao chép nó bằng
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
0, nó sẽ chỉ sao chép tham chiếu vào mảng gốc chứ không phải giá trị của mảng. Để tạo một bản sao thực của một mảng, bạn cần sao chép giá trị của mảng theo một biến giá trị mới. Bằng cách đó, mảng mới này không tham chiếu đến địa chỉ mảng cũ trong bộ nhớ.# Sự cố với các giá trị tham chiếu
Nếu bạn từng xử lý Redux hoặc bất kỳ khung quản lý nhà nước nào. Bạn sẽ biết tính bất biến là siêu quan trọng. Hãy để tôi giải thích ngắn gọn. Một đối tượng bất biến là một đối tượng nơi trạng thái không thể được sửa đổi sau khi nó được tạo. Vấn đề với JavaScript là
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
2 có thể thay đổi. Vì vậy, điều này có thể xảy ra:Đó là lý do tại sao chúng ta cần sao chép một mảng:
# Có thể thay đổi so với các loại dữ liệu bất biến
Mutable:
- sự vật
- mảng
- function
Immutable:
Tất cả các nguyên thủy là bất biến.
- sợi dây
- con số
- boolean
- null
- chưa xác định
- Biểu tượng
# Chỉ bản sao nông
Xin lưu ý
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
3 chỉ đi sâu một cấp khi sao chép một mảng. Vì vậy, nếu bạn đang cố gắng sao chép một mảng đa chiều, bạn sẽ phải sử dụng các lựa chọn thay thế khác.Đây là một điều thú vị tôi học được. Bản sao nông có nghĩa là cấp độ đầu tiên được sao chép, mức độ sâu hơn được tham chiếu.referenced.
# function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
4 là một cách khác để nhân bản mảng
function copy[aObject] {
// Prevent undefined objects
// if [!aObject] return aObject;
let bObject = Array.isArray[aObject] ? [] : {};
let value;
for [const key in aObject] {
// Prevent self-references to parent object
// if [Object.is[aObject[key], aObject]] continue;
value = aObject[key];
bObject[key] = [typeof value === "object"] ? copy[value] : value;
}
return bObject;
}
_Thanks: @hakankaraduman_
_@hakankaraduman: _ Vâng, tôi cố gắng không sử dụng lây lan, nó làm tôi bối rối khi đọc mã vì nó làm hai việc, lan truyền hoặc thu thập theo ngữ cảnh
CJ J: Tôi nghĩ rằng cách tốt nhất là cách phù hợp nhất với ngữ nghĩa của hoạt động. Tôi thích sử dụng
4function copy[aObject] { // Prevent undefined objects // if [!aObject] return aObject; let bObject = Array.isArray[aObject] ? [] : {}; let value; for [const key in aObject] { // Prevent self-references to parent object // if [Object.is[aObject[key], aObject]] continue; value = aObject[key]; bObject[key] = [typeof value === "object"] ? copy[value] : value; } return bObject; }
# Tài nguyên
- MDN Web Docs - nguyên thủy
- Tài liệu web MDN - Cú pháp lan truyền
- MDN Web Docs - Slice
- Stack Overflow: Tại sao một yếu tố lan truyền không phù hợp để sao chép các mảng đa chiều?