I'm solving a problem where the task is to merge multiple objects from the input array and return a single object with all the keys and values merged. In case a key exists in one or more objects in the input array, the most recent value for that key should be stored in the final returned object.
An example -
var a={1:'1',2:'2',3:'3'},
b={3:'4',5:'6',6:'7',7:'8'},
c={5:'9',8:'9',6:'12',23:'35'}
o=[a,b,c];
The returned object should be -
{ '1': '1','2': '2','3': '4','5': '9','6': '12','7': '8','8': '9','23':'35' }
As an example of the duplicate key case, key 3 exists in both objects a and b, so in the final result the value is {3:'4'} because that is the most recent.
I want to use the spread syntax for Objects in this problem, but that solves only a part of it. What I mean is, if I use spread for each object individually, that works, like -
function foo() {
var a={'1':'1','2':'2','3':'3'},
b={'3':'4','5':'6','6':'7','7':'8'},
c={'5':'9','8':'9','6':'12','23':'35'},
arr = [a,b,c];
return {...arr[0], ...arr[1], ...arr[2]}
}
console.log(foo());
For this to work, I need to write out each array element with spread, as in the above snippet - ...arr[0], ...arr[1], ...arr[2]. However, the input array can contain any number of objects, so writing out each element is not feasible.
Normally, using spread on an iterable like an array, allows you to expand the array elements, like so-
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
console.log(lyrics)
Is it possible to use spread on the input array to collect all the individual objects, on which spread can be applied again, to get the final object?
You could just use Object.assign():
return Object.assign(...arr);
Here's a complete snippet:
function foo() {
var a={'1':'1','2':'2','3':'3'},
b={'3':'4','5':'6','6':'7','7':'8'},
c={'5':'9','8':'9','6':'12','23':'35'},
arr = [a,b,c];
return Object.assign(...arr);
}
console.log(foo());
Note that this implicitly modifies the first object in your array. If you don't want that, pass a new empty object as the first argument to Object.assign():
return Object.assign({}, ...arr);
You can directly use spread syntax on object to merge them.
function foo() {
var a={'1':'1','2':'2','3':'3'},
b={'3':'4','5':'6','6':'7','7':'8'},
c={'5':'9','8':'9','6':'12','23':'35'};
return {...a, ...b, ...c};
}
console.log(foo());
If you have an array, then you can use array#reduce and Object#assign.
var a={'1':'1','2':'2','3':'3'},
b={'3':'4','5':'6','6':'7','7':'8'},
c={'5':'9','8':'9','6':'12','23':'35'},
arr = [a,b,c];
var result = arr.reduce(function(r,o){
return Object.assign(r,o);
},Object.create(null));
console.log(result);
NOTE : The Rest/Spread Properties for ECMAScript proposal (stage 3) adds spread properties to object literals. It copies own enumerable properties from a provided object onto a new object.
Related
In JavaScript, you can have objects, like this:
var a = { foo: 12, bar: 34 };
Or arrays with key (named) indexes, like this:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
They're somewhat similar, but obviously not the same.
Now the strange thing is, JSON.stringify doesn't seem to take the array. No errors or anything, JSON.stringify(b) just results in [].
See this jsfiddle example. Am I doing something wrong, or do I just misunderstand how arrays work?
Javascript doesn't support Associative arrays (Like PHP).
var b = []; Declaring explicitly an array, when you are trying to create an Object.
Arrays in Javascript can only contain the Index approach of Arrays, while Objects are more of
Associative arrays.
If you change var b = []; to var b = {}; it will solve the problem.
var b = {} Declaring explicitly an Object.
Javascript arrays are objects. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Predefined_Core_Objects#Array_Object for details.
Note: if you supply a non-integer value to the array operator in the
code above, a property will be created in the object representing the
array, instead of an array element.
JSON supports only a subset of Javascript. See http://www.json.org/ for details.
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed
list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
A Javascript array that has properties created in the underlying object does not fit into either of these structures because it has both a collection of name/value pairs and an ordered list of values, so there is no simple way to represent such an object directly in JSON.
The JSON.stringify method is defined in the ECMAScript specification. For example, see http://www.ecma-international.org/ecma-262/5.1/#sec-15.12.3.
While there are many details, the bit that is relevant here is how object values are stringified:
If Type(value) is Object, and IsCallable(value) is false
If the [[Class]] internal property of value is "Array" then Return the result of calling the abstract operation JA with argument value.
Else, return the result of calling the abstract operation JO with argument value.
Given your array, despite the addition of parameters to the underlying object, the result is of stringifying the ordered set of array elements, not the underlying object.
There is nothing wrong about adding parameters to an array object, but they are not part of the array and functions or methods that handle arrays might ignore them or deal with them arbitrarily. You have seen that JSON.stringify ignores the additional parameters. Other functions might do otherwise - you will have to find out in each case.
While it is not wrong, it will probably be easier to understand if you do not add properties to array objects. If you want to add properties, start with a non-array object.
Rather than:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
You might use:
var b = {};
b['foo'] = 56;
b['bar'] = 78;
This snap is from IE explorer. See the array is still blank.
Actually the way of inserting the elements to the array is :
1. Use push()
2. insert the elements in the array during declaration
If you want to stringify the array you have to have the data inside the array.
So, now you want to stringify the key value pairs so you have to pass the object as the argument of JSON.stringify() as follows:
var test = {}; // Object
test['a'] = 'test';
test['b'] = []; // Array
test['b'].push('item');
test['b'].push('item2');
test['b'].push('item3');
var json = JSON.stringify(test);
alert(json);
Solution to your problem now:
Note: Console of Google Chrome is giving different result, which is a bug in Google Chrome.
I'm implementing a native module for node and trying to return something that looks like an array but is backed by native data. At the moment I'm creating an ObjectTemplate and using SetIndexedPropertyHandler so I can handle attempts to get indexes from JS. This all works, but from JS this just looks like an Object, not an Array. Is there any way I can make this look more like an array?
You can return Object.entries(object).
The Object.entries() method returns an array of a given
object's own enumerable property [key, value] pairs, in the same
order as that provided by a for...in loop (the difference being that a
for-in loop enumerates properties in the prototype chain as well).
const obj = {a:1, b:2, c:3};
console.log(Object.entries(obj));
All arraylike objects must have length. As long as they have that property, you can borrow Array functions and run them on your object (e.g. Array.prototype.forEach.call(obj, ...)), or in ES6 run Array.from on it:
obj = {
0: "foo",
1: "bar",
length: 2
};
// ES5 way to get a real array:
console.log(Array.prototype.slice.call(obj));
// ES6 way to get a real array:
console.log(Array.from(obj));
If you actually want to return an array and not an arraylike object, then I suggest you use array = Array::New() and array->Set(index, element) instead of ObjectTemplate. There's an example in this question.
You could consider using a Proxy around a real array, with traps/handlers that interface with your native object. There's a performance penalty to using proxies (don't try to iterate over a proxied array if it's an important, hot code path), but they let you do just about anything.
var _arr = [];
var arraylike = new Proxy(_arr, {
get: function (target, prop) {
// Interface with your native object here.
if (prop === "length") return 20;
return "hello";
}
});
// Consume
> arraylike.length
20
> arraylike[5]
"hello"
> arraylike instanceof Array
true
> Array.isArray(arraylike)
true
It's also perfectly valid to prototypically inherit from Array in javascript.
What’s the difference between “{}” and “[]” while declaring a JavaScript array?
Normally I declare like
var a=[];
What is the meaning of declaring the array as var a={}
Nobody seems to be explaining the difference between an array and an object.
[] is declaring an array.
{} is declaring an object.
An array has all the features of an object with additional features (you can think of an array like a sub-class of an object) where additional methods and capabilities are added in the Array sub-class. In fact, typeof [] === "object" to further show you that an array is an object.
The additional features consist of a magic .length property that keeps track of the number of items in the array and a whole slew of methods for operating on the array such as .push(), .pop(), .slice(), .splice(), etc... You can see a list of array methods here.
An object gives you the ability to associate a property name with a value as in:
var x = {};
x.foo = 3;
x["whatever"] = 10;
console.log(x.foo); // shows 3
console.log(x.whatever); // shows 10
Object properties can be accessed either via the x.foo syntax or via the array-like syntax x["foo"]. The advantage of the latter syntax is that you can use a variable as the property name like x[myvar] and using the latter syntax, you can use property names that contain characters that Javascript won't allow in the x.foo syntax.
A property name can be any string value.
An array is an object so it has all the same capabilities of an object plus a bunch of additional features for managing an ordered, sequential list of numbered indexes starting from 0 and going up to some length. Arrays are typically used for an ordered list of items that are accessed by numerical index. And, because the array is ordered, there are lots of useful features to manage the order of the list .sort() or to add or remove things from the list.
When you declare
var a=[];
you are declaring a empty array.
But when you are declaring
var a={};
you are declaring a Object .
Although Array is also Object in Javascript but it is numeric key paired values.
Which have all the functionality of object but Added some few method of Array like Push,Splice,Length and so on.
So if you want Some values where you need to use numeric keys use Array.
else use object.
you can Create object like:
var a={name:"abc",age:"14"};
And can access values like
console.log(a.name);
var a = [];
it is use for brackets for an array of simple values.
eg.
var name=["a","b","c"]
var a={}
is use for value arrays and objects/properties also.
eg.
var programmer = { 'name':'special', 'url':'www.google.com'}
It can be understood like this:
var a= []; //creates a new empty array
var a= {}; //creates a new empty object
You can also understand that
var a = {}; is equivalent to var a= new Object();
Note:
You can use Arrays when you are bothered about the order of elements(of same type) in your collection else you can use objects. In objects the order is not guaranteed.
they are two different things..
[] is declaring an Array:
given, a list of elements held by numeric index.
{} is declaring a new object:
given, an object with fields with Names and type+value,
some like to think of it as "Associative Array".
but are not arrays, in their representation.
You can read more # This Article
Syntax of JSON
object = {} | { members }
members = pair | pair, members
pair = string : value
array = [] | [ elements ]
elements = value | value elements
value =
string|number|object|array|true|false|null
In JavaScript Arrays and Objects are actually very similar, although on the outside they can look a bit different.
For an array:
var array = [];
array[0] = "hello";
array[1] = 5498;
array[536] = new Date();
As you can see arrays in JavaScript can be sparse (valid indicies don't have to be consecutive) and they can contain any type of variable! That's pretty convenient.
But as we all know JavaScript is strange, so here are some weird bits:
array["0"] === "hello"; // This is true
array["hi"]; // undefined
array["hi"] = "weird"; // works but does not save any data to array
array["hi"]; // still undefined!
This is because everything in JavaScript is an Object (which is why you can also create an array using new Array()). As a result every index in an array is turned into a string and then stored in an object, so an array is just an object that doesn't allow anyone to store anything with a key that isn't a positive integer.
So what are Objects?
Objects in JavaScript are just like arrays but the "index" can be any string.
var object = {};
object[0] = "hello"; // OK
object["hi"] = "not weird"; // OK
You can even opt to not use the square brackets when working with objects!
console.log(object.hi); // Prints 'not weird'
object.hi = "overwriting 'not weird'";
You can go even further and define objects like so:
var newObject = {
a: 2,
};
newObject.a === 2; // true
[ ] - this is used whenever we are declaring an empty array,
{ } - this is used whenever we declare an empty object
typeof([ ]) //object
typeof({ }) //object
but if your run
[ ].constructor.name //Array
so from this, you will understand it is an array here Array is the name of the base class.
The JavaScript Array class is a global object that is used in the construction of arrays which are high-level, list-like objects.
In JavaScript, you can have objects, like this:
var a = { foo: 12, bar: 34 };
Or arrays with key (named) indexes, like this:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
They're somewhat similar, but obviously not the same.
Now the strange thing is, JSON.stringify doesn't seem to take the array. No errors or anything, JSON.stringify(b) just results in [].
See this jsfiddle example. Am I doing something wrong, or do I just misunderstand how arrays work?
Javascript doesn't support Associative arrays (Like PHP).
var b = []; Declaring explicitly an array, when you are trying to create an Object.
Arrays in Javascript can only contain the Index approach of Arrays, while Objects are more of
Associative arrays.
If you change var b = []; to var b = {}; it will solve the problem.
var b = {} Declaring explicitly an Object.
Javascript arrays are objects. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Predefined_Core_Objects#Array_Object for details.
Note: if you supply a non-integer value to the array operator in the
code above, a property will be created in the object representing the
array, instead of an array element.
JSON supports only a subset of Javascript. See http://www.json.org/ for details.
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed
list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
A Javascript array that has properties created in the underlying object does not fit into either of these structures because it has both a collection of name/value pairs and an ordered list of values, so there is no simple way to represent such an object directly in JSON.
The JSON.stringify method is defined in the ECMAScript specification. For example, see http://www.ecma-international.org/ecma-262/5.1/#sec-15.12.3.
While there are many details, the bit that is relevant here is how object values are stringified:
If Type(value) is Object, and IsCallable(value) is false
If the [[Class]] internal property of value is "Array" then Return the result of calling the abstract operation JA with argument value.
Else, return the result of calling the abstract operation JO with argument value.
Given your array, despite the addition of parameters to the underlying object, the result is of stringifying the ordered set of array elements, not the underlying object.
There is nothing wrong about adding parameters to an array object, but they are not part of the array and functions or methods that handle arrays might ignore them or deal with them arbitrarily. You have seen that JSON.stringify ignores the additional parameters. Other functions might do otherwise - you will have to find out in each case.
While it is not wrong, it will probably be easier to understand if you do not add properties to array objects. If you want to add properties, start with a non-array object.
Rather than:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
You might use:
var b = {};
b['foo'] = 56;
b['bar'] = 78;
This snap is from IE explorer. See the array is still blank.
Actually the way of inserting the elements to the array is :
1. Use push()
2. insert the elements in the array during declaration
If you want to stringify the array you have to have the data inside the array.
So, now you want to stringify the key value pairs so you have to pass the object as the argument of JSON.stringify() as follows:
var test = {}; // Object
test['a'] = 'test';
test['b'] = []; // Array
test['b'].push('item');
test['b'].push('item2');
test['b'].push('item3');
var json = JSON.stringify(test);
alert(json);
Solution to your problem now:
Note: Console of Google Chrome is giving different result, which is a bug in Google Chrome.
I've read many answers here relating to 'by value' and 'by reference' passing for sending arrays to javascript functions. I am however having a problem sending an array to a function and leaving the original array unaltered. This example llustrates the problem:
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;
}
I can't understand why anything in this function should alter the original array.
calling this function directly changes the original array if the function call is assigned to a new array:
myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];
anotherArray = new Array();
anotherArray = myFunction(myArray);
// myArray gets modified!;
I tried using .valueOf() to send the primitive:
anotherArray = myFunction(myArray.valueOf());
// myArray gets modified!;
I have even tried breaking the array down element by element and sub-element by sub-element and assigning all to a new 2-d array and the original array still gets modified.
I have also joined the sub-elements to a string, processed them, split them back into arrays and the original array still gets modified.
Please, does any one know how I can pass the array values to a function and not have the passed array change?
Inside your function there's this:
funcArray = new Array();
funcArray = someArray;
This won't actually copy someArray but instead reference it, which is why the original array is modified.
You can use Array.slice() to create a so-called shallow copy of the array.
var funcArray = someArray.slice(0);
Modern versions of ES also support destructuring expressions, which make it look like this:
const funcArray = [...someArray];
The original array will be unaltered, but each of its elements would still reference their corresponding entries in the original array. For "deep cloning" you need to do this recursively; the most efficient way is discussed in the following question:
What is the most efficient way to deep clone an object in JavaScript?
Btw, I've added var before funcArray. Doing so makes it local to the function instead of being a global variable.
Make a copy of the array that you can use.
A simple way to do this is by using var clone = original.slice(0);
With ES6, you can use the rest element syntax (...) within a destructuring expression to perform a shallow copy directly in the parameter list, allowing you to keep the original array unaltered.
See example below:
const arr = [1, 2, 3, 4, 5];
function timesTen([...arr]) { // [...arr] shallow copies the array
for(let i = 0; i < arr.length; i++) {
arr[i] *= 10; // this would usually change the `arr` reference (but in our case doesn't)
}
return arr;
}
console.log(timesTen(arr));
console.log(arr); // unaltered
The above is useful if you have an array of primitives (strings, booleans, numbers, null, undefined, big ints, or symbols) because it does a shallow copy. If you have an array of objects, or an array of arrays (which are also technically just objects), you will want to perform a deep clone to avoid modifying the array and its references. The way to do that in modern-day JS is to use a structured clone, which helps deal with many of the shortcomings of deep cloning with the JSON.stringify() technique as previously used:
function myFunction(someArray) {
const funcArray = structuredClone(someArray);
...
}
What about destructuring assignment (ES6+, check compatibility)? Nice and clean solution.
function myFunction(someArray) {
for(let i = 0; i < someArray.length; i++)
{
someArray[i].reverse();
}
return someArray;
}
let myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];
// Using destructuring assignment.
// NOTE: We can't just use `[...myArray]` because nested arrays will still be copied by reference.
let anotherArray = myFunction([...myArray.map(nested => [...nested])]);
console.log({original: myArray, copy: anotherArray});
A variable pointing to an array is a reference to it. When you pass an array, you're copying this reference.
You can make a shallow copy with slice(). If you want a full depth copy, then recurse in sub objects, keeping in mind the caveats when copying some objects.
If you need to do this with an object, try this fancy trick...
MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));
A generic solution would be...
// 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);
This works for objects as well as arrays.
Very effective when you need deep cloning or you don't know what the type is.
Deep cloning example...
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
Using the JSON parser to clone is not the most performant option!
It doesn't clone functions only JSON supported data types
Cannot clone circular references
by default in javascript except objects and arrays, everything is copy-by-value
but if you want to use copy-by-value for arrays: use [yourArray].slice(0)
and for objects use Object.assign(target, ...sources)
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]);
This answer has been edited. Initially I put forth that the new operator handled the solution, but soon afterward recognized that error. Instead, I opted to use the concat() method to create a copy. The original answer did not show the entire array, so the error was inadvertently concealed. The new output shown below will prove that this answer works as expected.
aArray: 0, 1, 2
aArrayCopy: A changed value., 1, 2