In my view I want to create a new object to return instead of the object that is passed to my map function. I would like to do some validation and add some fields to the new object. My map function for the view looks like this (there isn't a reduce):
function(doc) {
if(doc.type == "mytype") {
var newobj = null;
if( doc.someObjField ) {
newobj = doc.someObjField; //LINE 5: want a copy but get a reference
}
else {
newobj = new Object(); //field didn't exist create a new object
}
newobj.superId = doc._id; //these fields get added to the DB
newobj.superName = doc.name;
newobj.newField = doc.field;
emit(doc._id, newobj);
}
}
The problem is that when this view runs, it ends up adding some new fields to the documents in the database. I cannot see the fields when editing the doc in Futon, but they show up in every view of the document.
I think this is because because of LINE 5 creates a reference to that field of the document instead of a copy. Does this mean I have to include a clone() function in all my views to get what I want? Maybe I'm thinking about this wrong?
Update: I was using CouchDB version 1.0.0 and upgraded to version 1.0.1 and it seems that the behavior has changed. In the previous version when "doc" was modified in one view, the modification appeared in all views. In the newest version, this does not seem to be the case.
newobj = doc.someObjField does indeed make a reference and not a copy, so you'll will have to iterate over the properties of doc.someObjField and copy them over to a new object.
This is not that trivial, the following shows an example of how to make a shallow clone:
// get the class of an object, this is a lot better than messing with typeof and instanceof
function is(type, obj) {
return Object.prototype.toString.call(obj).slice(8, -1) === type;
}
function copy(val) {
if (is('Object', val)) { // shallow clone objects
var obj = {};
for (var f in val) {
if (val.hasOwnProperty(f)) {
obj[f] = val[f];
}
}
return obj;
} else {
return is('Array', val) ? val.slice() : val; // shallow clone arrays
}
}
Your code would look like this:
newobj = doc.someObjField ? copy(doc.someObjField) : {};
Now if you someObjField has objects or arrays as its properties those will yet again only be references, so you have to recursively clone them.
Related
Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:
let clone = {...original};
Is there anything wrong with this?
This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.
For deep cloning you'll need a different solution.
const clone = {...original} to shallow clone
const newobj = {...original, prop: newOne} to immutably add another prop to the original and store as a new object.
EDIT: When this answer was posted, {...obj} syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).
Use Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
However, this won't make a deep clone. There is no native way of deep cloning as of yet.
EDIT: As #Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))
If the methods you used isn't working well with objects involving data types like Date, try this
Import _
import * as _ from 'lodash';
Deep clone object
myObjCopy = _.cloneDeep(myObj);
You can do it like this as well,
let copiedData = JSON.parse(JSON.stringify(data));
if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
But the best way is to create a class that can return a clone of it self
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
Following on from the answer by #marcel I found some functions were still missing on the cloned object. e.g.
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing
enumerable: true
which meant it did not show up in
for(let key in item)
Instead I switched over to
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
which will include non-enumerable keys.
I also found that the prototype (proto) was not cloned. For that I ended up using
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: Frustrating that I could not find a built in function to do this.
structured Clone
you can Used this method
function Copy_Object(obj) { return structuredClone(obj); }
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
But Object.assign() not create a deep clone
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm.
In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).
I found a solution which seems to copy functions as well, correct me if this example is an error.
Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference
Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }
// i define a function for opt_resa :
opt_resa.func = function(){ alert('i am a function'); }
// copy object in modif.opt_resa :
var modif = { opt_resa : {} }
for ( var v in opt_resa ){
modif.opt_resa[v] = opt_resa[v];
}
// test
modif.opt_resa.breakfast_val = 1500;
// old value
console.log( opt_resa.breakfast_val );
// output : 900
// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500
// function copied
modif.opt_resa.func();
// this function works
All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.
The first example below shows object cloning using Object.assign which clones just till first level.
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
Using the below approach deep clones object
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:
let clone = {...original};
Is there anything wrong with this?
This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.
For deep cloning you'll need a different solution.
const clone = {...original} to shallow clone
const newobj = {...original, prop: newOne} to immutably add another prop to the original and store as a new object.
EDIT: When this answer was posted, {...obj} syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).
Use Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
However, this won't make a deep clone. There is no native way of deep cloning as of yet.
EDIT: As #Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))
If the methods you used isn't working well with objects involving data types like Date, try this
Import _
import * as _ from 'lodash';
Deep clone object
myObjCopy = _.cloneDeep(myObj);
You can do it like this as well,
let copiedData = JSON.parse(JSON.stringify(data));
if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
But the best way is to create a class that can return a clone of it self
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
Following on from the answer by #marcel I found some functions were still missing on the cloned object. e.g.
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing
enumerable: true
which meant it did not show up in
for(let key in item)
Instead I switched over to
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
which will include non-enumerable keys.
I also found that the prototype (proto) was not cloned. For that I ended up using
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: Frustrating that I could not find a built in function to do this.
structured Clone
you can Used this method
function Copy_Object(obj) { return structuredClone(obj); }
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
But Object.assign() not create a deep clone
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm.
In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).
I found a solution which seems to copy functions as well, correct me if this example is an error.
Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference
Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }
// i define a function for opt_resa :
opt_resa.func = function(){ alert('i am a function'); }
// copy object in modif.opt_resa :
var modif = { opt_resa : {} }
for ( var v in opt_resa ){
modif.opt_resa[v] = opt_resa[v];
}
// test
modif.opt_resa.breakfast_val = 1500;
// old value
console.log( opt_resa.breakfast_val );
// output : 900
// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500
// function copied
modif.opt_resa.func();
// this function works
All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.
The first example below shows object cloning using Object.assign which clones just till first level.
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
Using the below approach deep clones object
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
I have an issue that I am struggling to grasp. Any help would be greatly appreciated.
I have an Object, and I assign the current object state to a property on the current object.
example below:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: false
}
product.memory = product;
Now when I look at the product object within the console I get a inifinite recursion of Product.memory.Product.memory.Product....
screenshot below:
I know its something to do with that an object references itself, but I cannot seem to grasp the concept. Could someone explain?
The reason I am trying to do something like this is to save in local storage the current state of the object.
I hope I have made sense.
I assign the current object state to a property on the current object.
No, you created a property that referred to itself.
If you want to save the current state of the property then you need to clone the object.
If you want to create a (shallow) copy of an object then you can use:
function clone(obj) {
if(obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
return obj;
var temp = obj.constructor();
for(var key in obj) {
if(Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = obj[key];
delete obj['isActiveClone'];
}
}
return temp;
}
[code taken from here - and modified slightly to do a shallow copy rather than recursive deep copy]
then do:
product.memory = clone( product );
You may find you get the issues with recursion if you clone it a second time and it copies the product.memory along with the rest of the object. In that case just delete product.memory before doing subsequent clones.
Something like:
function saveCurrentState( obj ){
if ( 'memory' in obj )
delete obj.memory;
obj.memory = clone( obj );
}
Aside
If you want a deep copy then you can do:
function deepCopy(obj){
return JSON.parse(JSON.stringify(obj));
}
[As suggested here - but note the caveats it has for Date objects]
you could do your idea by clone the current product into new. We've Object.keys to get all attribute of object. So here is my idea :
product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: false
};
var keys = Object.keys(product);
var newProduct = {};
keys.forEach(function(key){
if(key === 'memory') return;
newProduct[key] = product[key];
});
product.memory = newProduct;
Instead of actually storing a reference to the object, you might want to transform that object's state. Maybe by cloning it onto a new object or possibly keeping it as a JSON string (which you'll want to do if you're using localStorage).
Since you will probably want to see the current state of the object whenever you check the memory property, you should make memory a function that does that transformation.
Maybe something like this:
var product = {
ropeType: 'blah',
ropePrice: 'blah',
ropeSections: {
name: 'blaah',
price: 'blaah'
},
memory: function() {
return JSON.stringify(this);
}
}
You can then call product.memory() and get its state in JSON.
This here is the problem:
product.memory = product;
You're assigning a reference to an object to itself. JavaScript passes objects by reference, so it's never going to store a clone of itself through assignment.
If you're looking to record modifications made to the object over time, the best way would be to use an array to hold cloned copies of it (or at least the properties that've changed).
To give you the quickest example:
var Product = function(){
};
var product = new Product();
product.history = [];
product.saveState = function(){
var changes = {};
for(var i in this){
/** Prevent infinite self-referencing, and don't store this function itself. */
if(this[i] !== this.history && this[i] !== this.saveState){
changes[i] = this[i];
}
}
this.history.push(changes);
};
Obviously, there're many better ways to achieve this in JavaScript, but they require more explanation. Basically, looping through an object to store its properties is inevitably going to trip up upon the property that they're being assigned to, so a check is needed at some point to prevent self-referencing.
I would like to make an extendDeep() function that does not make any garbage for GC.
The garbage collector need to be as inactive as possible.
ref.: https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript
This is the extendDeep() function I want to modify:
function extendDeep(parent, child) {
var i, toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === 'object') {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
The function does not have to return anything. since the retuned object is why the garbage is made.
It is assumed that all the propertis of the parent object is available by reference (reuse of objects)
A JS interpreter might avoid creating a string when doing toStr.call(parent[i]) but if you can't rely on them doing that optimization then you can avoid creating strings in the very common case by changing
toStr.call(parent[i]) === astr
to
parent[i] instanceof Array // Is a regular array.
|| (!(parent[i] instanceof Object) // Is cross-frame
&& 'number' === typeof parent[i].length // Might be an array
&& toStr.call(parent[i]) === astr) // So check the hidden [[Class]] property.
If you know you're dealing with objects created by constructors from the same frame (so no cross-frame object sharing) then you can get by with just
parent[i] instanceof Array
This is actually a more interesting question than I first thought. After reading the suggested link it is clear the articles author is advocating object pooling. So something like
function Pool(fConstructor, nMaxSize, fCleanFunction) {
this.aObjectPool = [];
this.nMaxSize = nMaxSize;
this.fCleanFunction = fCleanFunction;
this.fConstructor = fConstructor;
}
Pool.prototype.get = function() {
return this.aObjectPool.pop() || new this.fConstructor();
}
Pool.prototype.recycle = function(oObject) {
if (aObjectPool.length < this.nMaxSize) {
fCleanFunction(oObject);
this.aObjectPool.push(oObject);
}
}
function wipeArray(aArray) {
aArray.length = 0;
}
function wipeObject(oObject) {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
delete obj[p];
}
}
};
var oArrayPool = new Pool(Array, 50, wipeArray);
var oObjectPool = new Pool(Object, 50, wipeObject);
could be used to implement the pool. Then you'd replace the []'s and {}'s in the extend deep function with pool.get()'s.
Of course, for this to work you'd also need to ensure you were recycling old objects and arrays rather than just leaving them for garbage collection.
The 1st thing you need to decide is whether you want a clone or a copy, they are 2 different things.
The code you have given does a copy (and not a great one, because the use of hasOwnProperty means you could easily end up with non functional copies). A clone would be something like.
function Clone(){}
function clone(object) {
Clone.prototype = object;
return new Clone();
}
var objectToClone = {};
var clonedObject = clone(objectToClone);
The difference being that for a copy, changes to the original object will not affect the copy. For a clone, changes to the original object will affect the clone unless the clone has overwritten the property.
I have an object created from JSON via AJAX from the server. The object has several sub-objects in an array, e.g.:
obj.subObj1[0].value="abc";
obj.subObj1[1].value="abc";
obj.subObj2[0].value="abc";
Now I want to set some values in this object but I dont know if they already exist.
obj.subObj1[0].value="new Value"; // No Problem
obj.subObj2[1].value="new Value2"; // Problem because obj.subObj2[1] is no Object.
I would need to do obj.subObj2[1]={} first.
Because I have this problem very often I am looking for method to automate this. A method or class which does automatically create the needed object (or array if I use an integer).
It should be able to handle an infinite depth of such sub-objects. Like this:
var obj = TheObject();
obj.sub1.sub2[10].sub3[1].sub4='value';
Now automatically all needed sub-objects and arrays should be created.
Cannot really guarantee anything about cross-browser compatibility, but how about trying this on for size (works in Chrome):
// Safely sets value property of index of an array of an object.
function setObj(obj, subObjName, index, val) {
// Ensure the object exists
if (typeof obj == 'undefined') {
obj = new Object();
}
// Ensure the array property exists
if (typeof obj[subObjName] == 'undefined') {
obj[subObjName] = new Array();
}
// Ensure the array properties index exists
if (typeof obj[subObjName][index] == 'undefined') {
obj[subObjName][index] = {};
}
// Set the value
obj[subObjName][index].value = val;
// Return the object
return obj;
}
Example use:
<script type="text/javascript">
var obj;
obj = setObj(obj, "something", 1, "val");
setObj(obj, "something", 0, "someValue");
alert(obj.something[1].value);
alert(obj.something[0].value);
</script>
If you can assume that the referenced item in the array will be either undefined or an object it simplifies things. Of course the simple (non-automatic) way would be something like this:
if (!obj.subObj2[1]) obj.subObj2[1] = {};
obj.subObj2[1].value = "new Value2";
A not-very generic function to do it for you would be:
function setArrayObjectProp(arr, index, prop, val) {
if (!arr[index])
arr[index] = {};
arr[index][prop] = val;
}
// called as
setArrayObjectProp(obj.subObj2, 1, "value", "new Value2");
heloo
try testing the type of the array item first if its not object then equal it to the new object format {value:"new Value2"}
if(typeof(obj.subObj2[1])!='object')
{
obj.subObj2[1] = {value:"new Value2"};
}
else
{
obj.subObj2[1].value = "new Value2";
}