Javascript object reference by variable - javascript

I have an object like:
var theObject = {
keyName1: { keyName2: value2, keyName3: value3, keyName4: value40 },
...,
keyName10: { keyName2: value6, keyName3: value7, keyName4: value8 }
}
I know I can reference value7 by theObject["keyName10"]["keyName3"] or theObject.keyName10.keyName3
but what I need is to set a variable to something like the search path and somehow pass it to theObject and get value7 directly.
Something like:
var path = keyName10.keyName3;
var myValue = theObject(path);
Objects can be even further into the object inception.
Right now I'm solving it by horrible looking nestled for-loops.
Is there a better way I missed?

I just try to add a solution for fun. I will definitively do not use it like this, but the idea might work for your situation. I also question the efficiency of this approach.
var theObject = {
keyName1: { keyName2: value2, keyName3: value3, keyName4: value40 },
...,
keyName10: { keyName2: value6, keyName3: value7, keyName4: value8 }
}
var path = 'keyName10/keyName3';
function getProp(theObject, path){
var parts = path.split("/"),
idx = parts[0],
newParts = parts.splice(0, 1),
newPath = newParts.join("/"),
obj = theObject[idx];
// add some validation and error handling in case or error on path
// or missing property on obj
// I do not like the line below, would need to find a better way to see
// if the function return something or it does some recursion
// need to figure the right condition to see if we are at des
if(parts.length == 1) {
return obj;
} else {
return getProp(obj, newPath);
}
}
Might help: How do I check if an object has a property in JavaScript?

Why not create a getter function...
var path = 'keyName10/keyName3'
function getTheThing(key){
var parts = key.split("/")
return theObject[parts[0]][parts[1]]
}
var myValue = getTheThing(path)
You could make it more general, by passing the object, and the key to the getter, allowing the path to be used to access different objects...
var path = 'keyName10/keyName3'
function getTheThing(key, obj){
var parts = key.split("/")
return obj[parts[0]][parts[1]]
}
var myValue = getTheThing(path,theObject)

Related

Can we use concatenated values and variables for Object Keys?

I have a object
let x = { "propName": "response" }
Is there a way we can change the key name for the object. I would like to pass an index for the propName like
{ "prop1Name": "response" }
Is there a way to do this, I know I cant do it like this but, I tried it with
var obj = { "prop"+i+"Name": "response" };
console.log(obj);
But, it failed ofcourse.
Is there a way to do it?
You can use the new ES6/Babel syntax of {[keyfromvariable]:"value"}, so, in your case...
var i = "1";
var obj = { ["prop"+i+"Name"]: "response" };
console.log(obj);
If you don't have ES6/Babel as an option, you can define the object first and then use []...
var i = "1";
var obj = {};
obj ["prop"+i+"Name"] = "response" ;
console.log(obj);

Access dynamically created objects in Javascript

I am attempting to dynamically create an object with name-value pairs using html input fields. This is what i have so far:
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector);
for (var i=0;i<inputFields.length;i++) {
var attrValue = inputFields[i].getAttribute("name"),
value = inputFields[i].value,
newFieldObj = fieldObj[i] = {[attrValue]: value };
console.log(newFieldObj);
}
}
}
taskComplete.newTask('input');
The console log outputs:
Object {title: ""}
Object {description: ""}
Object {date: ""}
Question1:
How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
Question2:
Is there a way to combine these objects into a single object?
eg.
var obj = {
title: "",
description: "",
date: "",
}
code example with html: codepen.io
Hope this make sense. Thank you for any and all assistance.
I will answer your questions in the reverse order, makes more sense, you will see.
Question2: Is there a way to combine these objects into a single object?
Yes, I am happy to inform you that you absolutely can. Where you do
newFieldObj = fieldObj[i] = {[attrValue]: value };
simply do
fieldObj[attrValue] = value;
What this does, is the following: On the fieldObj, which is a plain {} set a key named after the value of attrValue and pair that key with the value value
Question1: How do i access these objects? they all share the same name eg. 'Object' so 'object.title' does not work.
In order to be able to access these objects, your newTask method should be returning them. So, at the end of your newTask method, simply do return fieldObj; like so
var taskComplete = {
newTask: function(arg) {
var fieldObj = {},
selector = arg,
inputFields = document.getElementsByClassName(selector),
attrValue,
value;
for (var i=0;i<inputFields.length;i++) {
attrValue = inputFields[i].getAttribute("name");
value = inputFields[i].value;
fieldObj[attrValue] = value;
}
return fieldObj;
}
}
and then store the returned value to a new variable like so:
var aFancyName = taskComplete.newTask('input');
Here's the modified pen: http://codepen.io/anon/pen/XdjKQJ
Not super clear on what you are trying to do here.
Instead of creating a new object for each iteration of your loop, why not just assign those properties to the fieldObj you already have?
Then you can just return that object and do whatever you want with it in the calling code:
'use strict';
// ** TASK OBJECT ** //
var taskComplete = {
newTask: function(selector) {
var fieldObj = {},
inputFields = document.getElementsByClassName(selector);
for (var i = 0; i < inputFields.length; i++) {
var attrKey = inputFields[i].getAttribute("name"),
value = inputFields[i].value;
fieldObj[attrKey] = value;
}
return fieldObj;
}
}
var o = taskComplete.newTask('input');
console.dir(o);
http://codepen.io/anon/pen/reMLPB?editors=0010

Var of multiple property's with empty values

I'm trying to create a var with a couple of empty property's in it using JavaScript. In other languages (for sure in swift, but I'm sure in others too,) this is called a struct.
What I want it to look like is something like this:
myStruct {
value1 : String,
value2 : String
}
The closest I found to that is objects (JavaScript Objects), but with that you would have to add values (to my knowledge).
After, I need to add myStruct to an array. I hope this is clear. What is the most efficient way to achieve this?
Method 1:
The simplest of achieving this is to use new in combination with the Function constructor.
var myStruct = function(prop1,prop2){
this.prop1 = prop1;
this.prop2 = prop2;
}
var myStructObj = new myStruct();
var myStructObj2 = new myStruct("prop1","prop2");
var myArr = [];
myArr.push(myStructObj);
myArr.push(myStructObj2);
console.log(myArr);
An enhancement would be to add default params to the constructor and pass arguments while creation.
var myStruct = function(arg1, arg2){
var prop1 = arg1 || "defaultProp1Value";
var prop2 = arg2 || "defaultProp2Value";
this.prop1 = prop1;
this.prop2 = prop2;
}
var myStructObj1 = new myStruct();
//myStructObj1.prop1 is "defaultProp1Value"
//myStructObj1.prop2 is "defaultProp2Value"
var myStructObj2 = new myStruct("prop1");
//myStructObj2.prop1 is "prop1"
//myStructObj2.prop2 is "defaultProp2Value"
var myArr = [];
myArr.push(myStructObj1);
myArr.push(myStructObj2);
With ES6, you can do this, you can now add default parameters to the constructor.
//This only works in ES6
// Will cause errors on browsers which have not yet added support
// WIll work when used along with a transpiler like Babel
var myStruct = function(arg1 = "defaultProp1", arg2 = "defaultProp2"){
this.prop1 = arg1;
this.prop2 = arg2;
}
var myStructObj1 = new myStruct();
//myStructObj1.prop1 is "defaultProp1Value"
//myStructObj1.prop2 is "defaultProp2Value"
var myStructObj2 = new myStruct("prop1");
//myStructObj2.prop1 is "prop1"
//myStructObj2.prop2 is "defaultProp2Value"
var myArr = [];
myArr.push(myStructObj1);
myArr.push(myStructObj2);
console.log(myArr);
You can read more about it here
Method : 2
Using call method. With this approach you can add props on the fly. Whenever you want to add a couple of props to an object with either null values or default values you can use this approach.
var addPropsFunction = function(a,b){
this.prop1 = a;
this.prop2 = b;
}
var myObj1 = {};
var myObj2 = {};
addPropsFunction.call(myObj1);
addPropsFunction.call(myObj2,"val1","val2");
console.log(myObj1);
console.log(myObj2);
Method : 3
ES6 Classes
class myStruct{
constructor(prop1,prop2){
this.prop1 = prop1;
this.prop2 = prop2;
}
}
var myObj = new myStruct();
console.log(myObj);
Es6 Fiddle - http://www.es6fiddle.net/ifz3rjcc/
In all cases, changing properties is the same.
To change prop1's value, all you have to do is
myStructObj.prop1 = "my val";
null is a value which means "no value". Assigning null to your properties yields exactly what you need.
Well you could do
var myArray = [
{"value1":"Value1Here", "value2":"Value2Here"},
{"value1":"Value1Here", "value2":"Value2Here"},
{"value1":"Value1Here", "value2":"Value2Here"}
];
(these values can be null)
or you could declare your object as above
and do :
myArray.push(yourObject)
I think by now you know how to create a struct in JS.
Now, to initialize properties with empty values:
You have to use either null or undefined based on your requirement.
These links can help you in understanding what and how exactly you have to proceed.
null and undefined
Which one to use?

_.function() version of underscore's _.property() function

Underscore has an Object function _.property(key) which returns a function that itself returns the 'key' property of any passed in object. For example:
var moe = {name: 'moe'};
var propFunction = _.property('name');
var value = propFunction(moe);
=> 'moe'
I'm wondering if there's a good way with Underscore to get the same behavior with an object's function in addition to just an object's property. I'm pretty sure there's not a single function for it, but I'm wondering if there's some reasonable combination of functions that together will do what I want. For example:
var moe = {getName: function() { return 'moe'; }};
var funcFunction = _.underscoreGoodnessHere('getName');
var value = funcFunction(moe);
=> 'moe'
This would be to remove some of the boilerplate in some pseudo-real code I have like this:
this.collection.filter(function(model) { return model.isHidden(); });
// could change to this:
this.collection.filter(_.underscoreGoodness('isHidden'));
For what it's worth, if there is not a great way to do what I've asked but you still have a better way to write my pseudo-real code above, I'd still love to hear that!
You're looking for the callback function that Underscore uses in _.invoke() - however that is not public. You can build it easily yourself:
_.method = function(name) {
var args = _.tail(arguments),
isFunc = _.isFunction(name);
return function(value) {
return (isFunc ? name : value[name]).apply(value, args);
};
};
You can create your own function which is based on _.property:
function callProperty(prop) {
var getProperty = _.property(prop);
return function(obj) {
return getProperty(obj)();
};
}
Shortest I can think of is using: _.result()
function functionProp(prop){
return function(obj){
return _.result(obj, prop);
};
}
Which will actually also work for non-function properties. So:
var moe = {getName: function() { return this.name; }, name: 'moe'};
'moe' == functionProp('getName')(moe);
'moe' == functionProp('name')(moe);
Underscore's property function doesn't distinguish between "functional properties" and "regular properties". To it, a function object stored under a property name is the property value itself. Extending the example you provided you see the following:
var moe = {getName: function() { return 'moe'; }};
var funcFunction = _.property('getName');
var getter = funcFunction(moe);
=> function() { return 'moe'; }
var value = getter();
=> 'moe'
funcFunction(moe)();
=> 'moe'
If you want to build your own, you can do something like the following:
function functionalProperty(name) {
var getter = _.property(name);
return function (o) { return getter(o); };
}
Or, if you want to support both types of properties with the same function, you could do this
function anyProperty(name) {
var getter = _.property(name);
return function (o) {
var val = getter(o);
return _.isFunction(val) ? val() : val;
};
}
Just be careful that you only use this for actual properties and not functions that you didn't really want to get invoked.

Can you use custom objects as properties of an object in javascript?

Suppose I create a custom object/javascript "class" (airquotes) as follows:
// Constructor
function CustomObject(stringParam) {
var privateProperty = stringParam;
// Accessor
this.privilegedGetMethod = function() {
return privateProperty;
}
// Mutator
this.privilegedSetMethod = function(newStringParam) {
privateProperty = newStringParam;
}
}
Then I want to make a list of those custom objects where I can easily add or remove things from that list. I decide to use objects as a way to store the list of custom objects, so I can add custom objects to the list with
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = true;
myListOfCustomObjects[customObjectInstance2] = true;
myListOfCustomObjects[customObjectInstance3] = true;
and remove custom objects from the list with
delete myListOfCustomObjects[customObjectInstance1];
but if i try to iterate through the list with
for (i in myListOfCustomObjects) {
alert(i.privilegedGetMethod());
}
I would get an error in the FireBug console that says "i.privilegedGetMethod() is not a function". Is there a way to fix this problem or an idiom in javascript to do what I want? Sorry if this is a dumb question, but I'm new to javascript and have scoured the internet for solutions to my problem with no avail. Any help would be appreciated!
P.S. I realize that my example is super simplified, and I can just make the privateProperty public using this.property or something, but then i would still get undefined in the alert, and I would like to keep it encapsulated.
i won't be the original object as you were expecting:
for (i in myListOfCustomObjects) {
alert(typeof i); // "string"
}
This is because all keys in JavaScript are Strings. Any attempt to use another type as a key will first be serialized by toString().
If the result of toString() isn't somehow unique for each instance, they will all be the same key:
function MyClass() { }
var obj = {};
var k1 = new MyClass();
var k2 = new MyClass();
obj[k1] = {};
obj[k2] = {};
// only 1 "[object Object]" key was created, not 2 object keys
for (var key in obj) {
alert(key);
}
To make them unique, define a custom toString:
function CustomObject(stringParam) {
/* snip */
this.toString = function () {
return 'CustomObject ' + stringParam;
};
}
var obj = {};
var k1 = new CustomObject('key1');
var k2 = new CustomObject('key2');
obj[k1] = {};
obj[k2] = {};
// "CustomObject key1" then "CustomObject key2"
for (var key in obj) {
alert(key);
}
[Edit]
With a custom toString, you can set the object as the serialized key and the value to keep them organized and still continue to access them:
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = customObjectInstance1;
myListOfCustomObjects[customObjectInstance2] = customObjectInstance2;
myListOfCustomObjects[customObjectInstance3] = customObjectInstance3;
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
The for iteration variable is just the index, not the object itself. So use:
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
and, in my opinion, if you use an Object as an array index / hash, it just would be converted to the string "Object", which ends up in a list with a single entry, because all the keys are the same ("Object").
myListOfCustomObjects =[
new CustomObject('someString'),
new CustomObject('someOtherString'),
new CustomObject('yetAnotherString')
]
you will get access to any element by index of array.

Categories

Resources