Is it necessary to create nested jSON objects before using it? - javascript

I think I've seen how to create a JSON object without first preparing it. This is how i prepare it:
obj = {
0:{
type:{}
},
1:{},
2:{}
};
Now I think I can insert a value like: obj.0.type = "type0"; But I'd like to create it while using it: obj['0']['type'] = "Type0";.
Is it possible, or do I need to prepare it? I'd like to create it "on the fly"!
EDIT
I'd like to create JS object "On the fly".
var obj = {};
obj.test = "test"; //One "layer" works fine.
obj.test.test = "test" //Two "layers" do not work... why?

obj = {
0:{
type:{}
},
1:{},
2:{}
};
Now i think i can insert value like: obj.0.type = "type0";
I guess you mean "assign" a value, not "insert". Anyway, no, you can't, at least not this way, because obj.0 is invalid syntax.
But I'd like to create it while using it: obj['0']['type'] = "Type0";
That's fine. But you need to understand you are overwriting the existing value of obj[0][type], which is an empty object ({}), with the string Type0. To put it another way, there is no requirement to provide an initialized value for a property such as type in order to assign to it. So the following would have worked equally well:
obj = {
0:{},
1:{},
2:{}
};
Now let's consider your second case:
var obj = {};
obj.test = "test"; //One "layer" works fine.
obj.test.test = "test" //Two "layers" do not work... why?
Think closely about what is happening. You are creating an empty obj. You can assign to any property on that object, without initializing that property. That is why the assignment to obj.test works. Then in your second assignment, you are attempting to set the test property of obj.test, which you just set to the string "test". Actually, this will work--because strings are objects that you can set properties on. But that's probably not what you want to do. You probably mean to say the previous, string value of obj.test is to be replaced by an object with its own property "test". To do that, you could either say
obj.test = { test: "test" };
Or
obj.test = {};
obj.test.test = "test";

You are creating a plain object in JavaScript and you need to define any internal attribute before using it.
So if you want to set to "Type0" an attribute type, inside an attribute 0 of an object obj, you cannot simply:
obj['0']['type'] = "Type0";
You get a "reference error". You need to initialize the object before using it:
var obj = {
0: {
type: ""
}
};
obj['0']['type'] = "Type0";
console.log(obj['0']['type']);

You could create your own function that takes key as string and value and creates and returns nested object. I used . as separator for object keys.
function create(key, value) {
var obj = {};
var ar = key.split('.');
ar.reduce(function(a, b, i) {
return (i != (ar.length - 1)) ? a[b] = {} : a[b] = value
}, obj)
return obj;
}
console.log(create('0.type', 'type0'))
console.log(create('lorem.ipsum.123', 'someValue'))

Is it necessary to create nested objects before using it?
Yes it is, at least the parent object must exist.
Example:
var object = {};
// need to assign object[0]['prop'] = 42;
create the first property with default
object[0] = object[0] || {};
then assign value
object[0]['prop'] = 42;
var object = {};
object[0] = object[0] || {};
object[0]['prop'] = 42;
console.log(object);
Create object with property names as array
function setValue(object, keys, value) {
var last = keys.pop();
keys.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var object = {};
setValue(object, [0, 'prop'], 42);
console.log(object);

Related

JavaScript Custom JSON Names Childs

I am trying to create a JSON Array:
let someJSON = {};
someJSON["number1"] = "someString";
works. But when I want to set a "Child" to number1 it fails:
someJSON["number1"]["date"] = "19.01.2017";
I tried some things but its not working :(
I need to create the JSON like this because I needs variables as parents
I am trying to create a JSON Array:
let someJSON = {};
someJSON["number1"] = "someString";
That's not a JSON array, that's a JavaScript object.
But when I want to set a "Child" to number1 it fails:
someJSON["number1"]["date"] = "19.01.2017";
That's because you're setting a property on a string primative. That will temporarily promote the string primative to an object, set the property, and then throw away the object, effectively doing nothing.
To make someJSON.number an object, create an object just like you did for someJSON and add properties to it. Or you can do it all at once:
let obj = {
number1: {
date: "19.01.2017"
}
};
If you want "someString" in there somewhere, just put it on another property:
let obj = {
number1: {
str: "someString",
date: "19.01.2017"
}
};
You have to create the "number1" object first. Note that you won't be able to set a string value for "number1" as it is now an object.
let someJSON = {};
someJSON["number1"] = {};
someJSON["number1"]["date"] = "19.01.2017";

Mongoose update on a string variable not working? [duplicate]

It's difficult to explain the case by words, let me give an example:
var myObj = {
'name': 'Umut',
'age' : 34
};
var prop = 'name';
var value = 'Onur';
myObj[name] = value; // This does not work
eval('myObj.' + name) = value; //Bad coding ;)
How can I set a variable property with variable value in a JavaScript object?
myObj[prop] = value;
That should work. You mixed up the name of the variable and its value. But indexing an object with strings to get at its properties works fine in JavaScript.
myObj.name=value
or
myObj['name']=value (Quotes are required)
Both of these are interchangeable.
Edit: I'm guessing you meant myObj[prop] = value, instead of myObj[name] = value. Second syntax works fine: http://jsfiddle.net/waitinforatrain/dNjvb/1/
You can get the property the same way as you set it.
foo = {
bar: "value"
}
You set the value
foo["bar"] = "baz";
To get the value
foo["bar"]
will return "baz".
You could also create something that would be similar to a value object (vo);
SomeModelClassNameVO.js;
function SomeModelClassNameVO(name,id) {
this.name = name;
this.id = id;
}
Than you can just do;
var someModelClassNameVO = new someModelClassNameVO('name',1);
console.log(someModelClassNameVO.name);
simple as this
myObj.name = value;
When you create an object myObj as you have, think of it more like a dictionary. In this case, it has two keys, name, and age.
You can access these dictionaries in two ways:
Like an array (e.g. myObj[name]); or
Like a property (e.g. myObj.name); do note that some properties are reserved, so the first method is preferred.
You should be able to access it as a property without any problems. However, to access it as an array, you'll need to treat the key like a string.
myObj["name"]
Otherwise, javascript will assume that name is a variable, and since you haven't created a variable called name, it won't be able to access the key you're expecting.
You could do the following:
var currentObj = {
name: 'Umut',
age : 34
};
var newValues = {
name: 'Onur',
}
Option 1:
currentObj = Object.assign(currentObj, newValues);
Option 2:
currentObj = {...currentObj, ...newValues};
Option 3:
Object.keys(newValues).forEach(key => {
currentObj[key] = newValues[key];
});

Create object by grouping camelCase properties

Recently I've found that I have had to create a object from attributes on a HTML tag. I am doing this in a AngularJS environment, so hyphenated attributes are converted to camelCase, but I could also do the same using data- attributes and dataset
So for example I have:
<element person-name="Grant" animation-jump="123" />
Which gives the object
{
"personName" : "Grant",
"animationJump" : "123"
{
My problem is that I then want to convert that camelCase object into a structured object:
{
"person" : {
"name" : "Grant" },
"animation" : {
"jump" : "123" }
}
I've created a JSFiddle of my QUint Unit Test https://jsfiddle.net/gdt3bonw/
It's actually working for the case I want which is only 1 level, but I would like to get it working for any number of levels because I foresee that it will be needed and so I can release the code publicly.
We will loop through the keys of the object using reduce, building up the result. We decompose each key into its components, such as personName into person and name. We loop over these components, creating subobjects if they do not already exist. Finally, we add the final component to the innermost subobject as a property with the value in question.
Object.keys(input).reduce((result, key) => {
var parts = key.match( /(^|[A-Z])[a-z]+/g) . map(part => part.toLowerCase());
var leaf = parts.pop();
var obj = result;
parts.forEach(part => obj = obj[part] = obj[part] || {});
obj[leaf] = input[key];
return result;
}, {});
You can't use that in this way, and I don't think that it would be a logic proposal. Below I explain why it wouldn't.
obj[["animation","jump"]] = "123"
replace it with
obj["animation"]["jump"] = "123"
and it's all fine.
Why I don't support your idea?
It's messy to use, there is no style in doing that.
There is no logic in using an array as an object key
There is another way of calling an object item by key: using a dot, and that won't support your idea. I think everyone can imagine why.
Why do you need to convert the attribute to camelCase in the first place..? Just do
function arrayToStructuredObject(obj,props){
if (props.length){
obj[props[0]] = props.length > 1 ? {} : value;
arrayToStructuredObject(obj[props.shift()],props);
}
return obj;
}
var props = "animation-jump-tremendous-pinky".split("-"),
value = "123",
obj = {},
sobj = {};
sobj = arrayToStructuredObject(obj, props);
Besides i would like to remind that using the bracket notation to create a property is only possible if the reference that the bracket notation is used upon is predefined as an object. Such as
var o1; // <- undefined
o1["myProp"] = 1; // Uncaught TypeError: Cannot set property 'myProp' of undefined
while
var o2 = {}; // Object {}
o2["myProp"] = 1; // <- 1
then again
o2["myProp"]["myOtherProp"] = 2; // <- 2 but won't type coerce o2.myProp to Object
So speaking of proposals, i am not sure if utilizing bracket notation directly over undefined variables yet as another object creation pattern makes sense or not.
Well in any case one complete solution would be
var inp = {"personName" : "Grant", "animationJump" : "123", "fancyGirlTakesARide" : "987"},
result = Object.keys(inp).reduce(function(p,c,i){
var props = c.replace(/[A-Z]/g, m => "-" + m.toLowerCase()).split("-");
return arrayToStructuredObject(p,props,inp[c])
},{});
function arrayToStructuredObject(obj,props,val){
if (props.length){
obj[props[0]] = props.length > 1 ? {} : val;
arrayToStructuredObject(obj[props.shift()],props,val);
}
return obj;
}
Though I loved the method of splitting the camelCase props by a look-ahead (/?=[A-Z]/) it takes an extra job of lower casing the whole array of prop strings regardless they are already lowercase or not. So i guess this might be slightly faster. (..or not due to the recursive nature of it)
This is not the best solution, but you can actually use arrays as key, in this particular situation, by converting them to a string:
obj[["animation","Jump"].join()] = "123";
This will work with your original object.
A solution, which uses Regex to split camel case string.
var obj = { "animationsJump": "123", "animationsRun": "456", "animationsHide": "789", "personName": "Grant", "personPetsDog": "Snowy", "personPetsCat": "Snowball" },
newObject = {};
Object.keys(obj).forEach(function (k) {
var path = k.split(/(?=[A-Z])/).map(function (s) {
return s.toLowerCase();
}),
last = path.pop();
path.reduce(function (r, a) {
r[a] = r[a] || {};
return r[a];
}, newObject)[last] = obj[k];
});
document.write('<pre>' + JSON.stringify(newObject, 0, 4) + '</pre>');

Getting a reference to an array element

While I realize that an array, as a non-primitive data type, is handled by references in JavaScript, not by value, any particular element of that array could be a primitive data type, and I assume then that it is not assigned by reference.
I'd like to know how to get a reference to an individual element in an array so that I don't have to keep referring to the array and the index number while changing that element?
i.e.
var myElement=someArray[4]
myElement=5
//now someArray[4]=5
Am I misinterpreting various docs that imply but do not explicitly state that this is not the intended behavior?
You can make a copy of an array element, but you can't create a value that serves as an alias for an array property reference. That's also true for object properties; of course, array element references are object property references.
The closest you could get would be to create an object with a setter that used code to update your array. That would look something like:
var someArray = [ ... whatever ... ];
var obj = {
set element5(value) {
someArray[5] = value;
}
};
Then:
obj.element5 = 20;
would update someArray[5]. That is clearly not really an improvement over someArray[5] = 20.
edit — Now, note that if your array element is an object, then making a copy of the element means making a copy of the reference to the object. Thus:
var someArray = [ { foo: "hello world" } ];
var ref = someArray[0];
Then:
ref.foo = "Goodbye, cruel world!";
will update the "foo" property of the object referenced by someArray[0].
You can always pass around a closure to update this:
var myUpdater = function(x) {
someArray[4] = x;
}
myUpdater(5);
If you want read/write capabilities, box it:
var makeBox = function(arr, n) {
return {
read: function() { return arr[n]; },
write: function(x) { arr[n] = x; }
};
}
// and then:
var ptr = makeBox(someArray, 4);
ptr.read(); // original
ptr.write(newValue);
someArray[4]; // newValue

Javascript setter and getter with key for object

I have an object in a variable var o={};
I want to do something like what .push() method doing in array for my object.
JS code:
// Array:
var ar=[];
ar.push('omid');
ar.push('F');
var got=ar[1];
// above code is standard but not what I'm looking for !
/*-------------------------------------*/
// Object:
var obj={};
/* obj.push('key','value'); // I want do something like this
var got2=obj.getVal('key'); // And this
*/
Is this possible at all ?
var obj = {}
// use this if you are hardcoding the key names
obj.key = 'value'
obj.key // => 'value'
// use this if you have strings with the key names in them
obj['key2'] = 'value'
obj['key2'] // => 'value'
// also use the second method if you have keys with odd names
obj.! = 'value' // => SyntaxError
obj['!'] = 'value' // => OK
Since Object-Literals use a Key->Value model, there is no JS method to "push" a value.
You can either use Dot Notation:
var Obj = {};
Obj.foo = "bar";
console.log(Obj);
Or Bracket Notation:
var Obj = {},
foo = "foo";
Obj[foo] = "bar";
Obj["bar"] = "foo";
console.log(Obj);
Consider reading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects, as arming yourself with this knowledge will be invaluable in the future.
Here is some javascript magic that makes it work.
Take a look.
var obj = {};
Object.defineProperty(obj,'push',{
value:function(x,y){
this[x]=y;
}
});
obj.push('name','whattttt'); <<<this works!!!
obj;
//{name:'whattttt'}
obj.name or obj['name']..
//whattttt
The reason i defined .push function using Object.defineProperty because i didn't want it to show up as a property of object. So if you have 3 items in object this would have always been the 4th one. And mess up the loops always. However, using this method. You can make properties hidden but accessible.
Though i don't know why you would use this method when there is already a easy way to do it.
to assign a value do this
obj.variable = 'value';
if value key is number or weird do this...
obj[1] = 'yes';
to access number or weird name you also do that
obj[1];
and finally to assign random keys or key that has been generated in code, not hard coded, than use this form too.
var person= 'him';
obj[him]='hello';

Categories

Resources