How to access property in object according to array - javascript

so i have an array like this:
var arr=[one, lol];
and an object like this
var obj={
one:{
lol:11234
}
}
How do I make it so if i do obj[lol] then it will print out 11234? Keep in mind I don't know how long the array is and answers like console.log(obj[one][lol]) doesn't work. Thanks in advance.

You can store the previous property's value (initially obj) and continue to loop until end of array like so:
var arr = ['one', 'two', 'three'];
var obj = {
one: {
two: {
three: 11234
}
}
}
var currentProp = obj;
for(var i = 0; i < arr.length; i++) {
currentProp = currentProp[arr[i]];
}
console.log(currentProp);
The above code will start at the object obj, then loop until the array's length, and reassign currentProp to the next property in the array as it goes. In this case, this is what it does:
First iteration, access obj[arr[0]], which is one, and assign it to currentProp
Second iteration, access obj[arr[0]][arr[1]] or one[arr[1]], which is two, and assign it to currentProp
Third iteration, access obj[arr[0]][arr[1]][arr[2]] or two[arr[2]], which is three, and assign it to currentProp. Loop then terminates as it has reached end of the list.
In the end, the value of the last property will be in currentProp, and will correctly output 11234.

You need to try like this :
obj["one"]["lol"]
JsFiddle : https://jsfiddle.net/3we2ohy6/1/

Since you are just looking up a property value it is simpler to do:
console.log(obj.one.lol);
Doing it using the square brackets the way you have it JS thinks both the one and LOL are variables. Unless you wrap them in quotes.
console.log(obj['one']['lol');
You will not get to the value you are looking for the way you are doing it unless you create a function that either restructures the obj object or you feed it the obj.one as a property.

You could use Array#reduce, because this returns the object you need, without keeping a reference outside.
function set(object, path, value) {
var last = path.pop();
path.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var obj = {};
set(obj, ['one', 'lol'], '11234');
console.log(obj);

Related

How to refactor/fix algorithim from mutating a reference to using inline variable

The function takes an input path like a.b.c and should output a nested structure json like:
{
a: {
b: {
c: {}
}
}
}
The algorithm using iterative style is:
function stringToObj(path, obj) {
var parts = path.split(".");
var part;
while ((part = parts.shift())) {
if (typeof obj[part] != "object") obj[part] = {};
obj = obj[part]; // line 6
}
}
Current usage:
let result = {};
stringToObj("a.b.c", result);
console.log(result); // outputs the json
JsFiddle
The problem:
It relies mutating the obj parameter on line 6.
I would like to not rely upon passing the result object, and rather create one inside the function. Doing so results in different results. A desired example usage:
const result = stringToObj("a.b.c"); // result should be the json
Context:
The exercise is for learning purpose. Main objective is understanding why removing obj and rewriting the function as per follows doesn't work as expected:
function stringToObj(path) {
var obj = {};
var parts = path.split(".");
var part;
while ((part = parts.shift())) {
if (typeof obj[part] != "object") obj[part] = {};
obj = obj[part]; // line 6
}
return obj;
}
After splitting by .s, you can use reduceRight to start at the last property, c, while taking an initial value of an empty object. Inside the callback, use a computed property to return a new object containing the old object at the property being iterated over:
const stringToObj = str => str.split('.').reduceRight(
(lastObj, prop) => ({ [prop]: lastObj }), {}
);
console.log(stringToObj('a.b.c'));
If you're not familiar with it, reduceRight is like reduce, except that it iterates starting from the last element in the array and going backwards, instead of starting from the first element of the array and going forwards. On each iteration, the callback is called, where the first argument (here, lastObj) is the value returned from the last iteration, and the second argument is the current item of the array being iterated over.
You can also reverse the array of properties and use reduce instead of reduceRight, which might be easier to understand at a glance, but it's a bit less elegant:
const stringToObj = str => str.split('.').reverse().reduce(
(lastObj, prop) => ({ [prop]: lastObj }), {}
);
console.log(stringToObj('a.b.c'));
Also, don't mix var and let. If you're going to use ES2015 syntax - which you should - consider always using const, and only use let when you must reassign. Never use var, it has too many gotchas to be worth using in modern code.

Variable value is not changing according to the variable

So here's the thing. I've declared the following variables to concat my object:
var newObj = obj[property];
var fullObj = newObj[id];
Then I'm matching the value of "fullObj" with the value of another obj named "Array". I do it like this:
fullObj = Array;
Then "fullObj" gets the new value, but the original object, which is something like: "obj.property.id" does not. Any ideas?
EDIT:
This is the function
function updateData(obj, Array, id, property) {
var newObj = obj[property];
var fullObj = newObj[id];
fullObj = Array;
}
The property that I'm sending back is "obj", with all its inner elements (obj.property.id).
As you can see, "fullObj" is the same thing as saying that last object construction. Imagine something like "object.id["0"]. So imagine the value of "Array" is "object.id["1"]. I'm giving "fullObj" that value by matching them both, but the original object won't get it.
Am I being clear enough?
The problem is that you are re-assigning the value for the fullObj variable. You can access the referenced object like that, but you can't change it.
Anyway, i don't see the point of doing that the way you are doing it. You can assign the value directly like this:
function updateData(obj, Array, id, property) {
obj[property][id] = Array;
}
You changed the reference of fullObj to some other reference (Array). The reference of newObj[id] remains the same.
Example
var a = [1];
var b = a;
b = [2];
console.log(a, b); // it logs [1] [2]

Trying to prevent duplicate values to be added to an array.

Having an issue with my project when it comes to adding a duplicate value to an array on a click event.
when I push the clicked item's value to the array openedCards.push(card); the code allows for multiple item values to be added to the array thus creating a matched value with a single item.
I have tried wrapping this code like so if ($.inArray(card, openedCards) < 0)openedCards.push(card); i see that the match class is no longer being added to matching pairs, or any values for that matter.
here is the Here is the jsfiddle
With vanilla javascript you can do this like the following:
if (array.indexOf(value) === -1) array.push(value);
Where array is your array of value's that you don't want duplicates of.
Or, you can use the following es6 syntax:
if (array.includes(value) === false) array.push(value);
I think you are running into issues with using object reference vs value
While obj and obj2 have same value for underlying properties, they both return different values to $.inArray
arr = [];
obj = {}; obj.A = 2;
arr.push(obj);
obj2 = {}; obj2.A = 2;
console.log($.inArray(obj, arr)); // 0
console.log($.inArray(obj2, arr)); // -1
In this case, I would recommend using some other property of card to check for availability within the array
function containsCard(card, list) {​
return list.some(function(elem) {
return elem.A === card.A
})
}
arr = [];
obj = {}; obj.A = 2;
arr.push(obj);
obj2 = {}; obj2.A = 2;
console.log(containsCard(obj, arr)); // true
console.log(containsCard(obj2, arr)); // true
You can just use $.inArray(), like:
if(!$.inArray(value, array))array.push(value);

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

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);

Can I loop through a javascript object in reverse order?

So I have a JavaScript object like this:
foo = {
"one": "some",
"two": "thing",
"three": "else"
};
I can loop this like:
for (var i in foo) {
if (foo.hasOwnProperty(i)) {
// do something
}
}
Which will loop through the properties in the order of one > two > three.
However sometimes I need to go through in reverse order, so I would like to do the same loop, but three > two > one.
Question:
Is there an "object-reverse" function. If it was an Array, I could reverse or build a new array with unshift but I'm lost with what to do with an object, when I need to reverse-loop it's properties. Any ideas?
Thanks!
Javascript objects don't have a guaranteed inherent order, so there doesn't exist a "reverse" order.
4.3.3 Object An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive
value, object, or function. A function stored in a property of an
object is called a method.
Browsers do seem to return the properties in the same order they were added to the object, but since this is not standard, you probably shouldn't rely on this behavior.
A simple function that calls a function for each property in reverse order as that given by the browser's for..in, is this:
// f is a function that has the obj as 'this' and the property name as first parameter
function reverseForIn(obj, f) {
var arr = [];
for (var key in obj) {
// add hasOwnPropertyCheck if needed
arr.push(key);
}
for (var i=arr.length-1; i>=0; i--) {
f.call(obj, arr[i]);
}
}
//usage
reverseForIn(obj, function(key){ console.log('KEY:', key, 'VALUE:', this[key]); });
Working JsBin: http://jsbin.com/aPoBAbE/1/edit
Again i say that the order of for..in is not guaranteed, so the reverse order is not guaranteed. Use with caution!
Why there is no one has mentioned Object.keys() ?
you can get Array of Object's properties ordered as it is, then you can reverse it or filter it as you want with Array methods .
let foo = {
"one": "some",
"two": "thing",
"three": "else"
};
// Get REVERSED Array of Propirties
let properties = Object.keys(foo).reverse();
// "three"
// "two"
// "one"
// Then you could use .forEach / .map
properties.forEach(prop => console.log(`PropertyName: ${prop}, its Value: ${foo[prop]}`));
// PropertyName: three, its Value: else
// PropertyName: two, its Value: thing
// PropertyName: one, its Value: some
There is no way to loop through an object backwards, but if you recreate the object in reverse order then you are golden! Be cautions however, there is nothing that says the order of the object will stay the same as it changes and so this may lead to some interesting outcome, but for the most part it works...
function ReverseObject(Obj){
var TempArr = [];
var NewObj = [];
for (var Key in Obj){
TempArr.push(Key);
}
for (var i = TempArr.length-1; i >= 0; i--){
NewObj[TempArr[i]] = [];
}
return NewObj;
}
The just do the swap on your object like this-
MyObject = ReverseObject(MyObject);
The loop would then look like this-
for (var KeysAreNowBackwards in MyObject){
alert(MyObject[KeysAreNowBackwards]);
}
This answer is similar to a couple of the others, but some users might find the code below easier to copy-paste for their own uses:
Object.keys(foo).reverse().forEach(function(key) { console.log(foo[key]) });
For an object "foo" as described in the question, this code will output the object elements in reverse order: "else", "thing", "some"
You can use
Object.keys
One thing to take care of is that it returns a sorted list of keys (if the keys are numerical). You might need to change it accordingly.
a = {'d':'stack','l':'overflow','b':'out','a':'first','z':'empty'}
out = Object.keys(a).reverse()
console.warn("When key contains characters : "+out)
a = {'1':'stack','4':'overflow','2':'out','5':'first','3':'empty'}
out = Object.keys(a).reverse()
console.warn("When key is a numerical string : "+out)

Categories

Resources