Creating new variable from another - javascript

What would be the best way to create a new array or object from another. Since doing
var oldvar = {x:1,y:2} //or [x,y]
var newvar = oldvar
will link them, what would be the bets best way to clone or cope the new variable?

Numbers in JavaScript
Numbers in JavaScript are what the spec calls 'Primitive Value Type'
From the specification about Numbers:
Number value # Ⓣ
primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value.
NOTE A Number value is a member of the Number type and is a direct representation of a number.
So in your case newvar will be a copy of oldvar and not a reference.
In JavaScript, Number, Boolean, undefined, null or String are value types.
When passing any of these 5 around, you are in fact passing values and not references, no need to clone those.
When you pass anything else around (Objects) need to use cloning since they are reference types.
When cloning objects in JavaScript there are two approaches.
Shallow Cloning
This means you clone 1 level deep. Assuming all our properties in the object are enumerable (This is usually the case if you haven't used property descriptors) you can use something like:
var a = {a:3,b:5};
var copy = {};
for(var prop in a){
copy[prop] = a[prop];
}
However, often we want to copy the object's own properties and not everything it might inherit from its prototype, so we can do:
var copy = {};
for(var prop in a){
if(a.hasOwnProperty(prop)){//check that the cloned property belongs to _a_ itself
copy[prop] = a[prop];
}
}
Note these two only shallow copy properties off a, they do not deal with setting the prototype, and clone all the properties by reference (Except properties who are primitive value types themselves :) ).
Deep copying
Deep copying means creating a clone of the object that is several levels deep. This calls to recursion since deep copying is defined as such (in psuedocode)
CopyObject(object)
If object is a primitive value type
return object
clone := Empty Object
For every member of object
Add CopyObject(member) as a property to clone
Return clone
We are applying the algorithm recursively on object properties of the clone.
Here is a sample implementation that I documented for you. It assumes ES5 (Chrome) but you can easily adapt it to other/older browsers. It does more stuff like treat Date and Regex like special cases. It also keeps a dictionary of properties it already handled so it will be able to handle circular references in an object. It is intended for learning and not for production use :) If you have any questions about it feel free.
var clone = function (a) {
var passedRefs = []; // Keep track of references you passed to avoid cycles
var passedRefCreated = [];
function clone2(a1) { // Inner function to handle the actual cloning
var obj;
if (typeof a1 !== "object" || a1 === null) { // Handle value type
return a1;
}
var locInpPassed = passedRefs.indexOf(a1); // Detect circular reference
if (locInpPassed !== -1) {
return passedRefCreated[locInpPassed];
}
passedRefs.push(a1); // Add the object to the references to avoid circular references later
if (a1 instanceof Date) { // Handle date and RegExp for special cases
obj = new Date(a1.getTime());
} else if (a1 instanceof RegExp) {
obj = new RegExp(a1);
}else if (Array.isArray(a1)){// handle arrays in order for Array.isArray to work. Thanks FizzyTea for catching this.
obj = [];
} else { // Create a new object with the prototype of the one we're cloning to support prototypical inheritance. Prototypes are _shared_
obj = Object.create(Object.getPrototypeOf(a1));
}
passedRefCreated[passedRefs.indexOf(a1)] = obj; // Add to the references created dict
Object.getOwnPropertyNames(a1).forEach(function (prop) { // Go through all the property, even the ones that are not enumerable
obj[prop] = clone2(a1[prop]); // Call the algorithm recursively, just like in the pseudo code above
});
return obj;
}
return clone2(a); // Call the inner function that has access to the dictionary
}
(For example, you can use a for... in loop to iterate through the properties).

I wrote 2 relation functions for deep copying arrays and objects in javascript:
function clone_object(o) {
var r = {};
for (var p in o) {
if (o[p].constructor == Array) {
r[p] = clone_array(o[p]);
} else if (o[p].constructor == Object) {
r[p] = arguments.callee(o[p]);
} else {
r[p] = o[p];
}
}
return r;
}
function clone_array(o) {
var r = [];
for (var p = 0, l = o.length; p < l; p++) {
if (o[p].constructor == Array) {
r[p] = arguments.callee(o[p]);
} else if (o[p].constructor == Object) {
r[p] = clone_object(o[p]);
} else {
r[p] = o[p];
}
}
return r;
}
Example:
var o = { name: 'Prototype', version: 1.5, authors: ['sam', 'contributors'] };
var o2 = clone_object(o);
o2.authors.pop();
alert(o.authors);
// -> ['sam', 'contributors']
alert(o2.authors);
// -> ['sam']

Related

Why doesn't JS provide a simple way to perform a deep copy on objects?

As someone used to python and C++, having an = copy objects by reference rather than value is not intuitive at all. Not just that, but there seems to be no direct way of copying objects to begin with. JSON.parse(JSON.stringify) is the closest option (if I know correctly), and even that has problems.
a) In a language where all variables are anyway treated as objects, why does the = operator distinguish between primitive and non-primitive data types to decide whether to copy by value or reference?
b) Why is copy by value not possible for objects?
c) What techniques are helpful for a beginner used to copying objects by value to code without it?
a) In a language where all variables are anyway treated as objects,
why does the = operator distinguish [...] ?
The =(assign) operator does not distinguish between primitive and non primitive data types. It kinda does the same for both, considering that equality is preserved after assignment (excluding exceptions e.g. NaN, ...).
b) Why is copy by value not possible for objects?
Wrong assumption in a) leads to this. Assignment is no copy and a copy of an object does not preserve equality.
Or think about:
var obj = {a: {b: 1}}
.
What is the value of obj.a ? It is just the reference to {b:1}.
c) What techniques are helpful for a beginner used to copying objects
by value to code without it?
There are many approaches for this. And two trivial cases.
As the first case one knows the layout of the object. Thus creates a template or constructor and passes all values into the corresponding properties.
As the second case one assumes a cyclic object containing everything possible in javascript (functions, regexp, symbols, undefined, ...) of depth n and builds something (not json.stringify).
For starters: possible duplicate
Assumptions:
primitive and non primitive data types have default getter,setter, ...
I guess it's because of the specific nature of JS. When you create an object like this:
let obj = {a: 3, b: 5}
And try to pass this object to another variable like this:
let obj2 = obj
You will still have only 1 object, but with 2 references, so if you try to modify obj.a it will also affect obj2.a.
That's why I created a way around for myself, which may not be the best, but here is it:
//A little helper
Object.isObject = function (object) {
return object !== null && object instanceof Object && !Array.isArray(object)
}
/*
* Array and Object copy work with each other, so every nested array are
* copied properly
*/
/*
* ARRAY
*/
Object.defineProperty(Array.prototype, 'copy', {
value: function (array){
if(!(Array.isArray(array))) throw new TypeError('passed value should be an instance of array')
if(array.length <= 0) {
console.warn('WARNING: Found nothing to copy')
return this
}
this.splice(0, this.length)
for(let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) this[i] = Array().copy(array[i])
else if (Object.isObject(array[i])) this[i] = Object().copy(array[i])
else this[i] = array[i]
}
return this
},
enumerable: false
})
/*
* OBJECT
*/
Object.defineProperty(Object.prototype, 'copy', {
value: function (object){
if(!object || !(Object.isObject(object))) return false
if(Object.entries(object) <= 0) {
console.warn('WARNING: Found nothing to copy')
return this
}
const props = Object.getOwnPropertyNames(this)
for (let i = 0; i < props.length; i++) delete this[props[i]]
const keys = Object.keys(object)
const values = Object.values(object)
for (let i = 0; i < keys.length; i++) {
if(Array.isArray(values[i])) this[keys[i]] = Array().copy(values[i])
else if(Object.isObject([values[i]])) this[keys[i]] = Object().copy(values[i])
else this[keys[i]] = values[i]
}
return this
},
enumerable: false
})
//create 2 arrays
let a = [3, 5, {a: 5}, [3, 1]]
let b = []
//copy array of a
b.copy(a)
//modify values
b[0] = 6
b[2].a = 1
b[3][0] = 'test'
console.log(a) //source
console.log(b)
As you can see in the example these 2 arrays (a and b) are completely different and have no relation to each other.
P.S. Sorry if I wrote something wrong, my english is not that good :O

What are the possible errors in this Object merging function?

I set out to find and understand a nice way to merge objects in Vanilla JS. My requirements for the function are very simple (borrowed from here):
Merge two objects x and y deeply, returning a new merged object with the elements from both x and y.
If an element at the same key is present for both x and y, the value from y will appear in the result.
The merge is immutable, so neither x nor y will be modified.
I came across this article that seems to provide a pretty good solution. After going through the code and understanding it (for the most part), I shortened it down to the following:
var extend = function() {
var extended = {};
var length = arguments.length;
// Merge the object into the extended object
var merge = function(obj) {
for (var prop in obj) {
//Check if a property is an object and another layer of merging is required
if (Object.prototype.toString.call(obj[prop]) === '[object Object]') {
extended[prop] = extend(true, extended[prop], obj[prop]);
} else {
extended[prop] = obj[prop];
}
}
};
// Loop through each object and conduct a merge
while (length--) {
var obj = arguments[length];
merge(obj);
}
return extended;
};
From the original solution I removed the check for a deep merge as I would like to deep merge by default, and this line, present before the currently merged property value is checked for being an object:
if ( Object.prototype.hasOwnProperty.call( obj, prop ) )
I don't understand this line - why should we check if the object whose properties are currently being looped through has the property from the current loop? I feel like I'm missing something.
So that's it. Are there any cases where this function wouldn't fulfil my requirements? Or break execution on any other way? Thank you.
if ( Object.prototype.hasOwnProperty.call( obj, prop ) )
I don't understand this line - why should we check if the object whose properties are currently being looped through has the property from the current loop?
Because for-in loops visit all of the enumerable properties of an object, including ones it inherits from its prototype. Whether you want to copy inherited properties over depends on your use cases for your extend function. Apparently in the original code, they didn't want to.
Example showing the difference:
var name;
var p = {inherited: "property"};
// Create an object using p as its prototype
var o = Object.create(p);
o.own = "property";
console.log("Without check");
for (name in o) {
console.log("- " + name);
}
console.log("With check");
for (name in o) {
if (Object.prototype.hasOwnProperty.call(o, name)) {
console.log("- " + name);
}
}

Javascript: make an deep clone/extend/copy function that does not make any garbage for GC

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.

Duplicate object in javascript

I see two ways to duplicate objects
1.
var a={c:1}
var b=a;
alert(b.c);//alert 1
2.
var a={c:2};
var b={};
for (i in a)
{b[i]=a[i];}
alert(b.c);//alert 1
The first are shorter than the second so what is the efficiency in the second example?
In the first version you don't duplicate/clone the object you simply make a extra reference to it:
var a = { a: 1 };
var b = a;
b.a = 2;
console.log(a.a); // 2;
To clone an object there is numbers of libraries that can do that for you:
var b = $.extend({}, a); // Make a shallow clone (jQuery)
var b _.extend({}, a); // Make a shallow clone (underscore.js)
var b = $.extend(true, {}, a); // Make a deep clone (jQuery);
Or you can do it natively:
Simple clone:
var b = {};
var prop;
for (prop in a) {
b[prop] = a[prop];
}
Scratch of a deep clone function:
function deepClone(obj) {
var r;
var i = 0,
var len = obj.length;
// string, number, boolean
if (typeof obj !== "object") {
r = obj;
}
// Simple check for array
else if ( len ) {
r = [];
for ( ; i < len; i++ ) {
r.push( deepClone(obj[i]) );
}
}
// Simple check for date
else if ( obj.getTime ) {
r = new Date( +obj );
}
// Simple check for DOM node
else if ( obj.nodeName ) {
r = obj;
}
// Object
else {
r = {};
for (i in obj) {
r[i] = deepClone(obj[i]);
}
}
return r;
}
The first does not create a copy, but just copies the reference, so a and b point towards the same object after the operation.
In the second case, however, each attribute is copied separately, thus creating a "real" copy of the object in a (as long as there are just primitive types in the properties, else you got the same problem at a deeper level).
So in the first case if you change b.c then a.c will also change, while in the second case it wont.
As others have stated here: the first assignment, assigns a new reference to an existing object, the second performs a shallow copy.By shallow I mean: only the base object will be copied, there is no recursion:
var a = {some:'propery',
another:{might:'be',
an: 'object, too'}
};
var b = {};
for(var p in a)
{
b[p] = a[p];
}
b.some = 'b\'s own property';
console.log(a.some);//property -> unaltered
console.log(b.some);//b's own property --> separate entities
b.another.might = 'foo';
console.log(a.another.might);//foo ==> b.another references a.another
To solve this issue, you would be forgiven to think that a simple recursive function would suffice:
var cloneObj = function(o)
{
var p,r = {};
for (p in o)
{//omitting checks for functions, date objects and the like
r[p] = (o[p] instanceof Object ? cloneObj(o[p]) : o[p]);
}
};
But be weary of circular references!
//assume a is the same object as above
a._myself = a;//<- a references itself
This will produce endless recursion, aka a deadlock scenario, unless you add a check for just such cases:
var cloneObj = function(o)
{
var p,r = {};
for (p in o)
{//Needs a lot more work, just a basic example of a recursive copy function
switch(true)
{
case o[p] instanceof Function:
r[p] = o[p];
break;
case o[p] instanceof Date:
r[p] = new Date(o[p]);
break;
case o === o[p]:
//simple circular references only
//a.some.child.object.references = a; will still cause trouble
r[p] = r;
break;
case o[p] instanceof Array:
r[p] = o[p].slice(0);//copy arrays
break;
default:
r[p] = o[p] instanceof Object ? cloneObj(o[p]) : o[p];
}
}
return r;
};
Now, this is quite verbose, and in most cases utter overkill, if all you want are two objects with the same data, but can be altered independently (ie don't reference the same object in memory), all you need is 1 line of code:
var a = {some:'propery',
another:{might:'be',
an: 'object, too'}
};
var b = JSON.parse(JSON.stringify(a));
Bottom line: assigning a reference is certainly more efficient: it doesn't require the object constructor to be called a second time, nor does it require an additional copy of any of the constants. The downside is: you end up with a single object and might inadvertently change/delete something that you assume is still there when you're using the other reference (delete b.some;/*some time later*/a.some.replace(/p/g,'q');//<--error)
The first copies the reference and does not duplicate the object, the second creates a new reference and then copies the members (which, in turn, if they are references will just copy the references only).
You might want to look at this other SO - Does Javascript equal sign reference objects or clones them?
It's not a question of efficiency it's ultimately about correctness. If you need to share a reference to an object between different code blocks (e.g. so that multiple pieces of code can share the same object) - then you simply rely on the fact that javascript passes by reference.
If, however, you need to copy an object between methods - then you might be able to use your simple example in your second code block (if your objects don't have other 'objects' in them), otherwise you might have to implement a deep-clone (see How to Deep clone in javascript, and pay attention to the answer(s) there - it's not a trivial business).

JavaScript: Testing primitives for equality

Let's say I have two objects that only have primitives as properties for members (e.g. the object has no functions or object members):
var foo = {
start: 9,
end: 11
};
var bar = {
start: 9,
end: 11
};
Given two objects like this, I want to know if all their members have the same values.
Right now I'm simpling doing:
if (foo.start === bar.start && foo.end == bar.end) {
// same member values
}
But I'm going to have to work with objects that may have dozens of these primitive members.
Is there anything built into JavaScript to easily allow me to compare them? What's the easiest way to compare all their values?
If both objects are Objects (e.g., created via literal notation [{}] or new Object, not by [say] new Date), you can do it like this:
function primativelyEqual(a, b) {
var name;
for (name in a) {
if (!b.hasOwnProperty(name) || b[name] !== a[name]) {
// `b` doesn't have it or it's not the same
return false;
}
}
for (name in b) {
if (!a.hasOwnProperty(name)) {
// `a` doesn't have it
return false;
}
}
// All properties in both objects are present in the other,
// and have the same value down to the type
return true;
}
for..in iterates over the names of the properties of an object. hasOwnProperty tells you whether the instance itself (as opposed to a member of its prototype chain) has that property. !== checks for any inequality between two values without doing any type coercion. By looping through the names of the properties of both objects, you know that they have the same number of entries.
You can shortcut this a bit if the implementation has the new Object.keys feature from ECMAScript5:
function primativelyEqual(a, b) {
var name, checkedKeys;
checkedKeys = typeof Object.keys === "function";
if (checkedKeys && Object.keys(a).length !== Object.keys(b).length) {
// They don't have the same number of properties
return false;
}
for (name in a) {
if (!b.hasOwnProperty(name) || b[name] !== a[name]) {
// `b` doesn't have it or it's not the same
return false;
}
}
if (!checkedKeys) {
// Couldn't check for equal numbers of keys before
for (name in b) {
if (!a.hasOwnProperty(name)) {
// `a` doesn't have it
return false;
}
}
}
// All properties in both objects are present in the other,
// and have the same value down to the type
return true;
}
Live example
But both versions of the above assume that the objects don't inherit any enumerable properties from their prototypes (hence my opening statement about their being Objects). (I'm also assuming no one's added anything to Object.prototype, which is an insane thing people learned very quickly not to do.)
Definitely possible to refine that more to generalize it, and even make it descend into object properties by the same definition, but within the bounds of what you described (and within the bounds of most reasonable deployments), that should be fine.
You can use a for in loop to loop through every property in an object.
For example:
function areEqual(a, b) {
for (var prop in a)
if (a.hasOwnProperty(prop) && a[prop] !== b[prop])
return false;
return true;
}
Any properties in b but not a will be ignored.
Y'know, something's just occurred to me. Basic object literals are called JSON. The easiest way to compare those two objects is
function equalObjects(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
If you need to use this in a browser that doesn't have native JSON support, you can use the open source JSON scripts

Categories