Nếu tôi sao chép một mảng, tôi sử dụng cloneArr = arr.slice()
Tôi muốn biết cách sao chép một đối tượng trong nodejs.
Nếu tôi sao chép một mảng, tôi sử dụng cloneArr = arr.slice()
Tôi muốn biết cách sao chép một đối tượng trong nodejs.
Câu trả lời:
Đối với các tiện ích và lớp học nơi không cần phải ép từng giọt hiệu suất, tôi thường gian lận và chỉ sử dụng JSON để thực hiện một bản sao sâu:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
Đây không phải là câu trả lời duy nhất hay câu trả lời thanh lịch nhất; tất cả các câu trả lời khác nên được xem xét cho các điểm nghẽn sản xuất. Tuy nhiên, đây là một giải pháp nhanh và bẩn, khá hiệu quả và hữu ích trong hầu hết các tình huống mà tôi muốn sao chép một hàm băm đơn giản của các thuộc tính.
newObj = obj.clone(args...);
Object.assign chưa được đề cập trong bất kỳ câu trả lời nào ở trên.
let cloned = Object.assign({}, source);
Nếu bạn đang sử dụng ES6, bạn có thể sử dụng toán tử spread:
let cloned = { ... source };
Tham khảo: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);
Có một số mô-đun Node ngoài đó nếu không muốn "tự tung tự tác". Cái này có vẻ ổn: https://www.npmjs.com/package/clone
Có vẻ như nó xử lý tất cả các loại nội dung, bao gồm cả các tham chiếu vòng tròn. Từ trang github :
clone master sao chép các đối tượng, mảng, đối tượng Date và đối tượng RegEx. Mọi thứ đều được sao chép đệ quy, vì vậy, bạn có thể sao chép ngày tháng trong các mảng trong các đối tượng, chẳng hạn. [...] Tham chiếu thông tư? Vâng!
Thật khó để thực hiện một hoạt động sao chép chung chung nhưng hữu ích bởi vì những gì nên được sao chép đệ quy và những gì chỉ nên được sao chép phụ thuộc vào cách đối tượng cụ thể được cho là hoạt động.
Một cái gì đó có thể hữu ích là
function clone(x)
{
if (x === null || x === undefined)
return x;
if (typeof x.clone === "function")
return x.clone();
if (x.constructor == Array)
{
var r = [];
for (var i=0,n=x.length; i<n; i++)
r.push(clone(x[i]));
return r;
}
return x;
}
Trong mã này, logic là
nullhoặc undefinedchỉ trả về cùng một trường hợp (trường hợp đặc biệt là cần thiết vì sẽ xảy ra lỗi khi thử xemclone phương thức nào không)clone phương thức? sau đó sử dụngChức năng sao chép này sẽ cho phép thực hiện các phương pháp sao chép tùy chỉnh một cách dễ dàng ... ví dụ:
function Point(x, y)
{
this.x = x;
this.y = y;
...
}
Point.prototype.clone = function()
{
return new Point(this.x, this.y);
};
function Polygon(points, style)
{
this.points = points;
this.style = style;
...
}
Polygon.prototype.clone = function()
{
return new Polygon(clone(this.points),
this.style);
};
Khi ở trong đối tượng, bạn biết rằng hoạt động sao chép chính xác cho một mảng cụ thể chỉ là một bản sao cạn thì bạn có thể gọi values.slice()thay vìclone(values) .
Ví dụ trong đoạn mã trên, tôi yêu cầu rõ ràng rằng một bản sao của một đối tượng đa giác sẽ sao chép các điểm, nhưng sẽ chia sẻ cùng một đối tượng kiểu. Nếu tôi cũng muốn sao chép đối tượng kiểu thay thế thì tôi có thể vượt qua clone(this.style).
.clonephương thức. Đây là cách tốt nhất để đối phó với các đối tượng nhân bản.
if (x.clone)nênif (typeof x.clone === 'function')
Không có phương pháp gốc nào để nhân bản các đối tượng. Dấu gạch dưới thực hiện _.clonelà một bản sao nông.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Nó hoặc cắt nó hoặc mở rộng nó.
Đây là _.extend
// extend the obj (first parameter)
_.extend = function(obj) {
// for each other parameter
each(slice.call(arguments, 1), function(source) {
// loop through all properties of the other objects
for (var prop in source) {
// if the property is not undefined then add it to the object.
if (source[prop] !== void 0) obj[prop] = source[prop];
}
});
// return the object (first parameter)
return obj;
};
Extend chỉ cần lặp lại tất cả các mục và tạo một đối tượng mới với các mục trong đó.
Bạn có thể triển khai triển khai ngây thơ của riêng mình nếu bạn muốn
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Có những lý do chính đáng để tránh nhân bản sâu vì không thể nhân bản các đóng.
Cá nhân tôi đã hỏi một câu hỏi deep cloning objects beforevà kết luận tôi đi đến là bạn không làm điều đó.
Khuyến nghị của tôi là sử dụng underscorevà đó là _.clonephương pháp dành cho nhân bản nông
Đối với một bản sao cạn, tôi thích sử dụng mẫu giảm (thường là trong một mô-đun hoặc tương tự), như sau:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Đây là jsperf cho một số tùy chọn: http://jsperf.com/shallow-copying
Câu hỏi cũ, nhưng có một câu trả lời thanh lịch hơn những gì được đề xuất cho đến nay; sử dụng utils._extend được tích hợp sẵn:
var extend = require("util")._extend;
var varToCopy = { test: 12345, nested: { val: 6789 } };
var copiedObject = extend({}, varToCopy);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 } }
Lưu ý việc sử dụng tham số đầu tiên với một đối tượng trống {} - điều này cho phép mở rộng rằng (các) đối tượng đã sao chép cần được sao chép sang một đối tượng mới. Nếu bạn sử dụng một đối tượng hiện có làm tham số đầu tiên, thì các tham số thứ hai (và tất cả các tham số tiếp theo) sẽ được sao chép hợp nhất sâu trên biến tham số đầu tiên.
Sử dụng các biến ví dụ ở trên, bạn cũng có thể làm điều này:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Tiện ích rất hữu ích, đặc biệt là khi tôi sử dụng để mở rộng trong AngularJS và jQuery.
Hy vọng điều này sẽ giúp người khác; ghi đè tham chiếu đối tượng là một nỗi khốn khổ, và điều này giải quyết nó mọi lúc!
Tùy thuộc vào những gì bạn muốn làm với đối tượng nhân bản của mình, bạn có thể sử dụng cơ chế kế thừa nguyên mẫu của javascript và đạt được một đối tượng được nhân bản thông qua:
var clonedObject = Object.create(originalObject);
Chỉ cần nhớ rằng đây không phải là một bản sao đầy đủ - tốt hơn hoặc tệ hơn.
Một điều tốt về điều đó là bạn thực sự chưa nhân bản đối tượng nên dung lượng bộ nhớ sẽ thấp.
Một số điều khó khăn cần nhớ mặc dù về phương pháp này là việc lặp lại các thuộc tính được xác định trong chuỗi nguyên mẫu đôi khi hoạt động hơi khác một chút và thực tế là bất kỳ thay đổi nào đối với đối tượng gốc cũng sẽ ảnh hưởng đến đối tượng nhân bản trừ khi thuộc tính đó cũng đã được đặt trên chính nó .
var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";
b.foo = "working"; console.log(a.foo); // still "broken";Tất nhiên phải lưu ý rằng những thay đổi trong đối tượng gốc sẽ được phản ánh trong "bản sao" và những thay đổi trong "bản sao" sẽ không được phản ánh trong đối tượng gốc - nhưng tôi sẽ không gọi nó là nguy hiểm - tất cả phụ thuộc vào những gì bạn muốn làm với bản sao của mình
Tôi đã triển khai một bản sao sâu đầy đủ. Tôi tin rằng nó là lựa chọn tốt nhất cho một phương pháp sao chép chung, nhưng nó không xử lý các tham chiếu theo chu kỳ.
parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;
obj2 = copy(obj)
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
parent.prop_chain=4
obj2.a = 15
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4
Mã này sao chép các đối tượng với nguyên mẫu của chúng, nó cũng sao chép các chức năng (có thể hữu ích cho ai đó).
function copy(obj) {
// (F.prototype will hold the object prototype chain)
function F() {}
var newObj;
if(typeof obj.clone === 'function')
return obj.clone()
// To copy something that is not an object, just return it:
if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
return obj;
if(typeof obj === 'object') {
// Copy the prototype:
newObj = {}
var proto = Object.getPrototypeOf(obj)
Object.setPrototypeOf(newObj, proto)
} else {
// If the object is a function the function evaluate it:
var aux
newObj = eval('aux='+obj.toString())
// And copy the prototype:
newObj.prototype = obj.prototype
}
// Copy the object normal properties with a deep copy:
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
if(typeof obj[i] !== 'object')
newObj[i] = obj[i]
else
newObj[i] = copy(obj[i])
}
}
return newObj;
}
Với bản sao này, tôi không thể tìm thấy bất kỳ sự khác biệt nào giữa bản gốc và bản được sao chép ngoại trừ nếu bản gốc được sử dụng đóng trên cấu trúc của nó, vì vậy tôi nghĩ rằng nó là một triển khai tốt.
Tôi hy vọng nó sẽ giúp
Đối tượng và Mảng trong JavaScript sử dụng lệnh gọi theo tham chiếu, nếu bạn cập nhật giá trị đã sao chép, nó có thể phản ánh trên đối tượng gốc. Để ngăn chặn điều này, bạn có thể sao chép sâu đối tượng, để ngăn tham chiếu được truyền, sử dụng lệnh chạy phương thức cloneDeep của thư viện lodash
npm cài đặt lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)