Exists a more elegant way to create an object from an array than this one?
var createObject = function(){
var myArray= generateArray();
var myObject = {
question : myArray[0],
answerA : myArray[1],
answerB : myArray[2],
answerC : myArray[3],
answerD : myArray[4]
};
return myObject;
}
What's your background? Python?
var values = generateArray();
var obj = {};
["question", "answerA", "answerB", "answerC", "answerD"].forEach(function(item, idx) {
obj[item] = values[idx];
});
return obj;
You could define an attribute map:
var createObject = function(){
// The map should have the attribute names set in order defined in `myArray`
var map = ["question", "answerA", "answerB", "answerC", "answerD"]
var myArray = generateArray();
var myObject = {};
for(var i in map)
myObject[map[i]] = myArray[i];
return myObject;
}
Try this to go beyond 'A', 'B', 'C', 'D':
function arrayToObject ( array ) {
return array.reduce(
function ( object, cell, index ) {
if (index > 0) object['answer' + String.fromCharCode(64 + index)] = cell;
else object['question'] = cell;
return object;
}, {}
);
}
If you would like to have a function that takes an array as an argument, and returns an object, this is how I would do it:
var toObject = function(arr) {
var newObj = {};
for(var i = 0; i < arr.length; i++) {
newObj[i] = arr[i];
}
return newObj;
};
However, keep in mind that Javascript arrays are simply objects with more methods available to them such as push(), pop(), and the length property.
Hope this helps!
Related
I'm trying to create a JS object dynamically providing a key and a value. The key is in dot notation, so if a string like car.model.color is provided the generated object would be:
{
car: {
model: {
color: value;
}
}
}
The problem has a trivial solution if the key provided is a simple property, but i'm struggling to make it work for composed keys.
My code:
function (key, value) {
var object = {};
var arr = key.split('.');
for(var i = 0; i < arr.length; i++) {
object = object[arr[i]] = {};
}
object[arr[arr.length-1]] = value;
return object;
}
your slightly modified code
function f(key, value) {
var result = object = {};
var arr = key.split('.');
for(var i = 0; i < arr.length-1; i++) {
object = object[arr[i]] = {};
}
object[arr[arr.length-1]] = value;
return result;
}
In the loop you should set all of the props but the last one.
Next set the final property and all set.
If you're using lodash you could use _.set(object, path, value)
const obj = {}
_.set(obj, "car.model.color", "my value")
console.log(obj)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Use namespace pattern, like the one Addy Osmani shows: http://addyosmani.com/blog/essential-js-namespacing/
Here's the code, pasted for convenience, all credit goes to Addy:
// top-level namespace being assigned an object literal
var myApp = myApp || {};
// a convenience function for parsing string namespaces and
// automatically generating nested namespaces
function extend( ns, ns_string ) {
var parts = ns_string.split('.'),
parent = ns,
pl, i;
if (parts[0] == "myApp") {
parts = parts.slice(1);
}
pl = parts.length;
for (i = 0; i < pl; i++) {
//create a property if it doesnt exist
if (typeof parent[parts[i]] == 'undefined') {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
}
// sample usage:
// extend myApp with a deeply nested namespace
var mod = extend(myApp, 'myApp.modules.module2');
function strToObj(str, val) {
var i, obj = {}, strarr = str.split(".");
var x = obj;
for(i=0;i<strarr.length-1;i++) {
x = x[strarr[i]] = {};
}
x[strarr[i]] = val;
return obj;
}
usage: console.log(strToObj("car.model.color","value"));
I would use a recursive method.
var createObject = function(key, value) {
var obj = {};
var parts = key.split('.');
if(parts.length == 1) {
obj[parts[0]] = value;
} else if(parts.length > 1) {
// concat all but the first part of the key
var remainingParts = parts.slice(1,parts.length).join('.');
obj[parts[0]] = createObject(remainingParts, value);
}
return obj;
};
var simple = createObject('simple', 'value1');
var complex = createObject('more.complex.test', 'value2');
console.log(simple);
console.log(complex);
(check the console for the output)
Here's a recursive approach to the problem:
const strToObj = (parts, val) => {
if (!Array.isArray(parts)) {
parts = parts.split(".");
}
if (!parts.length) {
return val;
}
return {
[parts.shift()]: strToObj(parts, val)
};
}
I have the following array:
["recordList", "userList", "lastChanged"]
And I want something like this:
lastChangedValue = "231231443234";
var object = {};
object = {
recordList: {
userList: {
lastChanged: lastChangedValue
}
}
}
How I can do this?
Thanks in advance.
Try this:
var array = ["recordList", "userList", "lastChanged"];
var value = "231231443234";
function arrayToObject(array, object, value) {
var ref = object;
for (var i=0; i<array.length-1; ++i) {
if (!ref[array[i]]) {
ref[array[i]] = {};
}
ref = ref[array[i]]
}
ref[array[array.length-1]] = value;
return object;
}
alert(JSON.stringify(arrayToObject(array, {}, value)));
You can iterate through property names and create one nested level of new object in each iteration:
var props = ["recordList", "userList", "lastChanged"];
var lastChangedValue = "231231443234";
var obj = {}
var nested = obj;
props.forEach(function(o, i) {
nested[o] = i === props.length - 1 ? lastChangedValue : {};
nested = nested[o];
});
console.log(obj);
There are probably a bunch of ways to do it, one way is with reduce
var keys = ["recordList", "userList", "lastChanged"];
var temp = keys.slice().reverse(),
lastChangedValue = "231231443234";
var result = temp.reduce( function (obj, val, ind, arr) {
if (ind===0) {
obj[val] = lastChangedValue;
return obj;
} else {
var x = {};
x[val] = obj;
return x;
}
}, {});
console.log(result);
Solving with recursion
var fields = ["recordList", "userList", "lastChanged"];
lastChangedValue = "231231443234";
var object = {};
(function addFields(o, i, v) {
if (i == fields.length - 1) {
o[fields[i]] = v;
return;
}
o[fields[i]] = {};
addFields(o[fields[i]], ++i, v)
})(object, 0, lastChangedValue);
alert(JSON.stringify(object));
If I do have the following code then empty the arry:
var a1 = [1,2,3];
a1 = [];
//returns []
But I'm trying to make a function to clear and undo clear the array, it's not working as expected:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
}
function undoClearArray(a){
a = storeArray;
}
clearArray(foo);
foo; //still returns ['f','o','o']
//but expected result is: []
Here's the problem:
You assign an array to a variable foo.
Then you pass this object to your function which stores it in another variable a. Now you have one object that two variable are pointing at. In the function you then reassign a to a different object an empty array []. Now a points at the empty object and foo still points at the original object. You didn't change foo by reassigning a.
Here's a concise way to store you're array:
var storeArray = [];
function clearArray(a){
while (a.length>0){
storeArray.push(a.shift()) //now a is empty and storeArray has a copy
}
}
I tried something different. Maybe it's dirty, but the storage itself is on the object.
the fiddle
//define the object to hold the old data
Object.defineProperty(Array.prototype, "storage", {
enumerable: false,
configureable: true,
get: function () {
return bValue;
},
set: function (newValue) {
bValue = newValue;
}
});
//define the prototype function clear to clear the data
Object.defineProperty(Array.prototype, "clear", {
enumerable: false,
writable: false,
value: function () {
this.storage = this.slice(0); //copy the data to the storage
for (var p in this) {
if (this.hasOwnProperty(p)) {
delete this[p]; //delete the data
}
}
return this; //return the object if you want assign the return value
}
});
//define the prototype function restore to reload the data
Object.defineProperty(Array.prototype, "restore", {
enumerable: false,
writable: false,
value: function () {
var a = this.storage.slice(0); //copy the storage to a local var
for (var p in this.storage) {
if (this.storage.hasOwnProperty(p)) {
this[p] = a[p]; //assign the pointer to the new variable
delete this.storage[p]; //delete the storage
}
}
return this;
}
});
var a = ['f','o','o'];
console.log(a); //--> displays ['f','o','o']
a.clear();
console.log(a); //--> displays []
a.restore();
console.log(a); //--> displays ['f','o','o']
You can use splice() method to delete all elements of an array likes below
function clearArray(a){
storeArray = a;
a.splice(0,a.length);
}
var a = [1,2,3,4];
var tempArr ;
clearArray = function() {
tempArr = a.slice(0);
a.length = 0;
}
undoArray = function() {
a = tempArr.slice(0);
}
Here is a small jsfiddle: http://jsfiddle.net/66s2N/
Here's working way of what you want to achieve:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a.slice(0);
for (var i=0; i<a.length; i++)
delete a[i];
a.length = 0;
}
function undoClearArray(a){
for (var i=0; i<storeArray.length; i++)
a.push(storeArray[i]);
}
console.log(foo);
clearArray(foo);
console.log(foo); //now foo is []
undoClearArray(foo);
console.log(foo); // now foo is ['f','o','o']
http://jsfiddle.net/44EF5/1/
When you do:
var a1 = [1,2,3];
a1 = [];
it's as if you've written:
var a1 = [1,2,3];
var a1 = [];
You're overwriting variables.
Now, why your approach doesn't work - in JS there's no passing by reference. MarkM response explains what's happening within the function.
Now, why does the above work - while you've got two variables pointing towards the same array, nothing prevents you from modifying that array. As such storeArray = a.slice(0) will create a copy of the array. Then by using delete we're removing all values of the array, and then as length isn't enumerable (so using for (var i in a) wouldn't help) we reassign the length of the array. This has removed the values of original array, while creating a new array assigned to storeArray.
function clearArray(a){
storeArray = a.slice(0);
return a.length = 0;
}
or set foo.length = 0;
Just update your both function with below ones
function clearArray(a){
storeArray = a.slice(0);
a.length = 0;
}
function undoClearArray(a){
a = storeArray;
return a;
}
in undoClearAray() we are returning the variable which have new reference(in your clearArray(), Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays). so use it as foo=undoClearArray(foo); for old values.
try
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
return a;
}
function undoClearArray(a){
a = storeArray;
}
foo = clearArray(foo);
foo; //returns []
You can use wrappers to do this quite nicely. First create a wrapper function with the additional methods defined, then create your array using that function instead of []. Here is an example (see JSFiddle):
var extendedArray = function() {
var arr = [];
arr.push.apply(arr, arguments);
arr.clearArray = function() {
this.oldValue = this.slice(0);
this.length = 0;
}
arr.undoArray = function() {
this.length = 0;
for (var i = 0; i < this.oldValue.length; i++) {
this.push(this.oldValue[i]);
}
}
return arr;
};
var a = extendedArray('f', 'o', 'o');
alert(a);
a.clearArray();
alert(a);
a.undoArray();
alert(a);
I face this problem a lots and I tired of writing conversion function
I can do
function toObject(arr) {
var rv = {};
for (var i = 0; i < arr.length; ++i)
rv[i] = arr[i];
return rv;
}
but is there short-cut for that? my case as below :
angular.forEach($scope.data, function(item){
if(thread.checked === true){
var links = item.url;
chrome.tabs.create(links, function(tab) {
});
}
});
I'm using chrome API where links is obj :
chrome.tabs.create(obj, function(tab) {
});
In an ES5 browser you can do:
var obj = {};
[0,1,2].forEach(function(v, i){obj[i] = v});
or
[0,1,2].forEach(function(v, i, arr){this[i] = v}, obj);
As a function:
function toObj(arr) {
var obj = {};
arr.forEach(function(v, i){obj[i] = v});
return obj;
}
If the object passed in may not be an array but an object with properties 0 to n, then:
function toObj(arr) {
var obj = {};
[].forEach.call(arr, function(v, i){obj[i] = v});
return obj;
}
I am trying to have a javascript object tree behave like a php associative array in the following way.
var key1 = 'a';
var key2 = 'b';
var key3 = 'c';
var obj[key1][key2][key3] = 'd';
However, in javascript I believe you need to define each property/object pair individually, forming deeper leaves. Something like:
var obj[key1] = {};
var obj[key1][key2] = {};
...
Is there a way to simplify or shorten this script?
Thanks
I don't know if there's a "natural" way to do it, but you could do it like this:
function phpLike(){};
phpLike.prototype.set = function ()
{
var l = arguments.length;
if (l<2) return;
var o = this;
for (var i=0; i<l-2; i++)
{
if (o[arguments[i]] === undefined) o[arguments[i]] = {};
o = o[arguments[i]];
}
o[arguments[l-2]] = arguments[l-1];
}
// Test
var key1 = 'a';
var key2 = 'b';
var key3 = 'c';
var obj = new phpLike();
obj.set(key1, key2, key3, 'd');
alert(obj[key1][key2][key3]);
function setPropertyByKeyPath(obj, path, val) {
var key;
while (path.length > 1) {
key = path.shift();
obj[key] = typeof obj[key] === "object" ? obj[key] : {};
obj = obj[key];
}
obj[path.shift()] = val;
}
var o = {};
setPropertyByKeyPath(o, ['foo', 'bar'], 5);
alert(o.foo.bar)
Not directly, as far as I know, but how about using a little helper function?
function kv1(k, v) {
var o = { };
o[k] = v;
return o;
}
var obj = kv1(key1, kv1(key2, kv1(key3, 'd')));
I just thought of an answer inspired by Will's post: Construct a json string and then eval().
var obj = eval("{" + key1 + ": {... }};");
This kind of fulfils my search for a more concise way of declaring an object tree and deep leaf. But, it is ugly, confusing and I would avoid it like the plague.
var obj = { key1: { key2: { key3: 'd' } } }
This syntax is the basis of the format known as JSON: http://en.wikipedia.org/wiki/JSON