Say I have an object like this (simplified):
var options = {
boxes: {
size: {
x: 15,
y: 18
},
shadow: {
[...]
}
};
And I have an array of names:
var names = ['boxes', 'size', 'x'];
What is an easy way to get/set a value inside the object according to the array, in this example it would be:
options.boxes.size.x = somevalue;
Any ideas?
There's no easy, built-in method for doing this. You'd have to write your own method:
function getPath(obj, props) {
for(var i = 0; i < props.length; i++) {
if (props[i] in obj) {
obj = obj[props[i]];
} else {
return; // not found
}
}
return obj;
}
function setPath(obj, value, props) {
for(var i = 0; i < props.length - 1; i++) {
if (props[i] in obj) {
obj = obj[props[i]];
} else {
return; // not found
}
}
obj[props[i]] = value;
}
alert(getPath(options, names)); // 15
setPath(options, 25, names);
alert(getPath(options, names)); // 25
Just use a loop that iterates the names and grabs the next nested object for the current name. Either a falsey value or the end of the array should halt the loop.
var obj = options;
var i = 0;
while (obj && i < names.length)
obj = obj[names[i++]];
Or simply use .reduce()
names.reduce(function(obj, name) {
return obj && obj[name];
}, options);
And of course you can name and reuse the function if you prefer.
function toPropertyIn(obj, name) {
return obj && obj[name];
}
names.reduce(toPropertyIn, options);
To make a getter/setter:
function nestedProp(obj, names, value) {
if (arguments.length > 1)
var setProp = names.pop();
var res = names.reduce(function(obj, name) {
return obj && obj[name];
}, options);
if (res && setProp !== undefined)
res[setProp] = value;
else
return res;
}
nestedProp(options, names, "foo"); // to set
var val = nestedProp(options, names); // to get
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)
};
}
intro:
I'm trying to write a deep copy method, but need to keep track of my visited nodes, so that I can link to the previously visitedNode instead of deep copying forever until stack overflow.
attempts:
var visitedNodes = {};
var obj = {}; obj.a = obj; // circular; can't use JSON.stringify)
var obj2 = {};
visitedNodes[obj] = "should need key obj (not obj2) to access this string";
console.log(visitedNodes[obj2]); // logs the string unfortunately
I don't have a unique way of storing the memory location -- it stores itself at [object Object] and I can't use JSON.stringify because it's a circular structure
I tried using var visitedNodes = new Map(); but still no dice
My current approach is to utilize the Array.prototype.indexOf function, but I don't know if it works with circular structures either, because I'm getting a stack overflow here too!!!
this.clone = function (item, visitedNodes) {
visitedNodes = visitedNodes || [];
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneObject = {};
visitedNodes.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = this.clone(item[i], visitedNodes);
}
}
return cloneObject;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(this.clone(item[j], visitedNodes));
}
return cloneArray;
} else {
return visitedNodes[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
};
the question:
Anyone have any ideas for getting a unique memory address so I can determine if I've been to the Object's reference before? I believe I could construct a unique hash based off Object.keys() and Object.prototype.constructor but that seems absurd and will give false positives if constructor is the same and the child keys are the same as the parent
In visitedNodes save the original reference, and create another array to save with same index the clone object to use when is a reference.
function deepClone(obj) {
var visitedNodes = [];
var clonedCopy = [];
function clone(item) {
if (typeof item === "object" && !Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (var i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
else if (typeof item === "object" && Array.isArray(item)) {
if (visitedNodes.indexOf(item) === -1) {
var cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (var j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
} else {
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not object, not array, therefore primitive
}
return clone(obj);
}
var obj = {b: 'hello'};
obj.a = { c: obj };
var dolly = deepClone(obj);
obj.d = 'hello2';
console.log(obj);
console.log(dolly);
the code running example:
http://jsbin.com/favekexiba/1/watch?js,console
The code in the answer of Fetz works great but breaks on Date objects. Here is a patched version:
const visitedNodes = [];
const clonedCopy = [];
function clone(item) {
if (typeof item === 'object') {
if (item instanceof Date) { // Date
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = new Date(item);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (XMLDocument && item instanceof XMLDocument) { // XML Document
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
const cloneObject = item.implementation.createDocument(item.documentElement.namespaceURI, null, null);
const newNode = cloneObject.importNode(item.documentElement, true);
cloneObject.appendChild(newNode);
clonedCopy.push(cloneObject);
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (!Array.isArray(item)) { // Object
if (visitedNodes.indexOf(item) === -1) {
visitedNodes.push(item);
var cloneObject = {};
clonedCopy.push(cloneObject);
for (const i in item) {
if (item.hasOwnProperty(i)) {
cloneObject[i] = clone(item[i]);
}
}
return cloneObject;
}
return clonedCopy[visitedNodes.indexOf(item)];
} else if (Array.isArray(item)) { // Array
if (visitedNodes.indexOf(item) === -1) {
const cloneArray = [];
visitedNodes.push(item);
clonedCopy.push(cloneArray);
for (let j = 0; j < item.length; j++) {
cloneArray.push(clone(item[j]));
}
return cloneArray;
}
return clonedCopy[visitedNodes.indexOf(item)];
}
}
return item; // not date, not object, not array, therefore primitive
}
return clone(obj);
I would've preferred to edit the answer of Fetz but the edit queue is full.
edit 19/07/2017: Added XML Document cloning as well
var keys1 = ["foo", "moreFoo"],
value1 = "bar",
keys2 = ["foo", "ultraFoo"],
value2 = "bigBar";
I'd like to make a function which would build me an object :
object {
foo : {moreFoo: "bar", ultraFoo: "bigBar"}
}
I thought of taking each one of my arrays and doing the following :
function recursiveObjectBuild(object, keys, value) {
var index = 0;
function loop(object, index) {
var key = keys[index];
//Property exists, go into it
if (key in object) {
loop(object[key], ++index);
//Property doesn't exist, create it and go into it
} else if (index < keys.length-1) {
object[key] = {};
loop(object[key], ++index);
//At last key, set value
} else {
object[key] = value;
return object;
}
}
return loop(object, 0);
}
Which should work IMO but doesn't (infinite loop, must be a stupid mistake but can't see it).
And I'm sure there must be a much simpler way
Try the following:
function objectBuild(object, keys, value) {
for (var i = 0; i < keys.length-1; i++) {
if (!object.hasOwnProperty(keys[i]))
object[keys[i]] = {};
object = object[keys[i]];
}
object[keys[keys.length-1]] = value;
}
Example usage (see it in action):
var object = {};
objectBuild(object, ["foo", "moreFoo"], "bar");
objectBuild(object, ["foo", "ultraFoo"], "bigBar");
// object --> {foo: {moreFoo: "bar", ultraFoo: "bigBar}}
Illustrative example:
d1 = {
"ean_code": ["OA13233394CN08", "8903327046534", "8903327014779"],
"balance_qty": [5, 10, 15]
}
And
d2 = {
"ean_code": ["OA13233394CN11", "OA13233394CN08", "8903327014779", "OA13233394CN09"],
"scanned_qty": [30, 5, 20, 10, - 1],
}
Output:
d3 = {
"ean_code": ["OA13233394CN08", "8903327046534", "8903327014779", "OA13233394CN11", "OA13233394CN09"],
"scanned_qty": [5, 0, 20, 30, 10],
"balance_qty": [5, 10, 15, 0, 0]
}
Explaination. d3['scanned_qty'][1] default value is 0, because value of d3['ean_code'][1] is belongs to d1['ean_code'] array and d1 object doesn't have scanned_qty key.
Best possible way to do this operation?
You just need a custom solution for your specific case.
Merge 2 objects with no sub-objects (no recursion required)
Final object's array fields must be the same length
Final object's array fields must preserve index coherency
Final object's array fields must use '0' as a default value
http://jsfiddle.net/8X5yB/4/
function customMerge(a, b, uniqueKey) {
var result = {};
var temp = {};
var fields = {};
// object 1
for(var x=0; x<a[uniqueKey].length; x++) {
id = a[uniqueKey][x];
if(temp[id] == null) temp[id] = {};
for(k in a) {
if(k != uniqueKey) {
fields[k] = '';
temp[id][k] = (a[k].length > x ? a[k][x] : 0);
}
}
}
// object 2
for(var x=0; x<b[uniqueKey].length; x++) {
id = b[uniqueKey][x];
if(temp[id] == null) temp[id] = {};
for(k in b) {
if(k != uniqueKey) {
fields[k] = '';
temp[id][k] = (b[k].length > x ? b[k][x] : 0);
}
}
}
// create result
result[uniqueKey] = [];
for(f in fields) result[f] = [];
for(k in temp) {
result[uniqueKey].push(k);
for(f in fields) {
result[f].push(temp[k][f] != null ? temp[k][f] : 0);
}
}
return result;
}
...
var obj = customMerge(d1, d2, "ean_code");
Let's assume you have o1 and o2 as object 1 and 2, respectively.
var key,
result = {}
i,
largestLength = 0,
copyIntoResult = function (obj, key) {
for (i = 0; i < obj[key].length; i += 1) {
if (result[key].indexOf(obj[key][i]) === -1) {
result[key].push(obj[key][i]);
}
}
};
for (key in o1) {
if (o1.hasOwnProperty(key) && o2.hasOwnProperty(key)) {
result[key] = [];
copyIntoResult(o1, key);
copyIntoResult(o2, key);
if (result[key].length > largestLength) {
largestLength = result[key].length;
}
} else if (o1.hasOwnProperty(key)) {
result[key] = [].concat(o1[key]);
if (o1[key].length > largestLength) {
largestLength = o1[key].length;
}
}
}
for (key in o2) {
if (o2.hasOwnProperty(key) && !result[key]) {
result[key] = [].concat(o2[key]);
if (o2[key].length > largestLength) {
largestLength = o2[key].length;
}
}
}
// result now has the merged result
for (key in result) {
if (result[key].length < largestLength) {
for (i = 0; i < (largestLength - result[key].length); i += 1) {
result[key].push('');
}
}
}
EDIT: Upon the edit to your question, you can have all the arrays be the same length by equalizing the arrays to the maximum array length of the merged result. However, the default "blank" entry is up to you (in this case, I just used an empty string).
function merge(a,b) {
var c = {};
for(key in a.keys()) {
c[key] = a[key].slice(0);
}
for(key in b.keys()) {
if(typeof c[key] == 'undefined') {
c[key] = b[key].slice(0);
} else {
var adds = b[key].filter(function(item){
return (a[key].indexOf(item) == -1);
});
c[key].concat(adds);
}
}
return c;
}
.keys() method since v1.8.5, snippet for older browsers.
filter since v1.6, snippet for older browsers.
concat since v1.2.
var arr = { foo : 1, bar: { baz : 2 }, bee : 3 }
function getter(variable) {
return arr[variable];
}
If I want 'foo' vs 'bee' I can just do arr[variable] - that's easy, and the function does that.
But what if I want to get arr.bar.baz AKA arr[bar][baz]?
What can I pass to the getter function that will let me do that, (and of course also let me get non-nested properties using the same function).
I tried getter('bar.baz') and getter('[bar][baz]') but those didn't work.
I suppose I can parse for dots or brackets (like here: In javascript, test for property deeply nested in object graph?). Is there a cleaner way? (Besides eval of course.)
Especially because I need to get the deeply set properly many many times in a loop for a bunch of array elements.
You can use a deep access function based on a string for the path. Note that you can't have any periods in the property names.
function getPropByString(obj, propString) {
if (!propString)
return obj;
var prop, props = propString.split('.');
for (var i = 0, iLen = props.length - 1; i < iLen; i++) {
prop = props[i];
var candidate = obj[prop];
if (candidate !== undefined) {
obj = candidate;
} else {
break;
}
}
return obj[props[i]];
}
var obj = {
foo: {
bar: {
baz: 'x'
}
}
};
console.log(getPropByString(obj, 'foo.bar.baz')); // x
console.log(getPropByString(obj, 'foo.bar.baz.buk')); // undefined
If the access string is empty, returns the object. Otherwise, keeps going along access path until second last accessor. If that's an ojbect, returns the last object[accessor] value. Otherwise, returns undefined.
Using ES6:
var arr = { foo : 1, bar: { baz : 2 }, bee : 3 };
var {foo, bar, bar: {baz}, bee} = arr;
Same as:
// var foo = 1;
// var bar = {baz: 2};
// var baz = 2;
// var bee = 3;
Using lodash:
https://lodash.com/docs#get
_.get(arr, 'bar.baz'); //returns 2;
_.get(arr, 'bar.baz[5].bazzz'); //returns undefined wont throw error;
_.get(arr, 'bar.baz[5].bazzz', 'defaultvalue'); // Returns defaultValue because result is undefined
A recursive way :
function getValue(obj, path) {
if (!path) return obj;
const properties = path.split('.');
return getValue(obj[properties.shift()], properties.join('.'))
}
const myObj = {
foo: {
bar: {
value: 'good'
}
}
}
console.log(getValue(myObj, 'foo.bar.value')); // good
How about change the getter function signature as getter('bar', 'baz') instead
function getter() {
var v = arr;
for(var i=0; i< arguments.length; i++) {
if(!v) return null;
v = v[arguments[i]];
}
return v;
}
ps. didn't test, but you get the idea ;)
A one liner for you:
const mock = {
target: {
"prop1": {
"prop2": {
"prop3": "sad"
}
}
},
path: "prop1.prop2.prop3",
newValue: "happy"
};
mock.path.split(".").reduce(
(acc, curr, i, src) =>
(curr === src[src.length - 1]) ? acc[src[src.length - 1]] = mock.newValue : acc[curr], mock.target);
console.log(mock.target); //? { prop1: { prop2: { prop3: 'happy' } } }
Here's a very simple one liner which grants you dynamic access via "foo.bar.baz" mechanism,
var obj = {
foo: {
bar: {
baz: 'foobarbaz'
}
}
}
const nestedAccess = "foo.bar.baz";
console.log(nestedAccess.split('.').reduce((prev, cur) => prev[cur], obj)) //'foobarbaz'
I have recently developed my own Object method to get an object property nested among objects and arrays regardless how deep it is. It utilizes a single line of recursive approach. Check this out.
Object.prototype.getNestedValue = function(...a) {
return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};
var myObj = { foo : 1, bar: { baz : 2 }, bee : 3 },
bazval = myObj.getNestedValue("bar","baz");
document.write(bazval);
Now let's check a deeper nested array object combo data structure
Object.prototype.getNestedValue = function(...a) {
return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};
var myArr = [{fox: [{turn:[857, 432]}]}, {sax: [{pana:[777, 987]}]}, {ton: [{joni:[123, 567]}]}, {piu: [{burn:[666, 37]}]}, {sia: [{foxy:[404, 696]}]}];
document.write(myArr.getNestedValue(3,"piu",0,"burn",1));
I believe being able to pass search parameters dynamically to existing array methods would make actions like searching, filtering or replacing of deeply nested structures much easy.
Using reduce we can fetch the value in single line of code.
const testobj = {b:{c:'1', d:{e:'2',f:'3'}}, g:{h:'3'}}
function fetchByDotOperator(object, value) {
return value.split('.').reduce((acc, curr) => acc[curr], object);
}
console.log(fetchByDotOperator(testobj,'b.d.e'))
You can access the functions arguments where you can pass any number of strings.
I also recommend using arr as a parameter for better encapsulation:
function getter() {
var current = arguments[0];
for(var i = 1; i < arguments.length; i++) {
if(current[arguments[i]]) {
current = current[arguments[i]];
} else {
return null;
}
}
return current;
}
var arr = { foo : 1, bar: { baz : 2 }, bee : 3 };
var baz = getter(arr, 'bar', 'baz');
function getPropertyByString(object, propString) {
let value = object;
const props = propString.split('.');
for (let index = 0; index < props.length; index += 1) {
if (props[index] === undefined) break;
value = value[props[index]];
}
return value;
};
const object = {
name: 'any_name',
address: {
number: 77,
test: {
name: 'test'
}
}
}
console.log(getPropertyByString(object, 'address.test.name'))
// test
Above answers help you access nested objects only, however you might also want to access data in an object/array data type. You can try this recusive method:
const getValue = (obj, key) => {
const keyParts = key.split(".");
return getValueHelper(obj, keyParts);
};
const getValueHelper = (obj, keyParts) => {
if (keyParts.length == 0) return obj;
let key = keyParts.shift();
if (Array.isArray(obj[key])) {
return obj[key].map((x) => getValueHelper(x, [...keyParts])).flat();
}
return getValueHelper(obj[key], [...keyParts]);
};
//Examples
let data1 = {
a: [{ b: { c: [{ d: [{ e: 1 }] }] } }, { b: { c: [{ d: [{ e: 2 }] }] } }],
};
console.log(getValue(data1, "a.b.c.d.e"));
//Output
//[ 1, 2 ]
let data2 = {
a:{b:1},
};
console.log(getValue(data2, "a.b"));
//Output
//1
p.s. Remove .flat() to get desired output for arrays.
Theres a function defined on this blog to safely read nested properties from a JS object
It allows you to mine an object for properties... ie.
safeRead(arr, 'foo', 'bar', 'baz');
and if any part of the object chain is null or undefined it returns an empty string....
let obj = {foo : {bar: {baz:1}}};
// -- simply
console.log(eval('obj.foo.bar.baz')); //-- 1
// -- safer
val = "";
try {
val = eval('Obj.foo.bar.baz')
}
catch(e) {
val = "empty"
}
// -- val = 1
// -- use at your risk ;)
Here I created a small suite of functions to 'get / 'set' / 'push' / 'pull' from object nested properties.
inputObject : Target object.
Ex: obj = {a:1, b:{c:2,d:3}}
propertyString : String containing the key to access.
Ex: "b.c"
Finally:
_getObjectValueByPathString(obj, "b.c") would return 2
function _getObjectValueByPathString(inputObject, propertyString) {
let splitStr = propertyString.split('.');
if (!inputObject.hasOwnProperty(splitStr[0])) return undefined;
if (splitStr.length === 1) {
return inputObject[splitStr[0]];
}
else if (splitStr.length > 1) {
let newPropertyString = "";
let firstValue = splitStr.shift();
splitStr.forEach((subStr, i) => {
newPropertyString = i === 0 ? subStr : newPropertyString.concat(`.${subStr}`);
});
return _getObjectValueByPathString(inputObject[firstValue], newPropertyString);
}
else {
throw "Invalid property string provided";
}
}
function _setObjectValueByPathString(inputObject, propertyString, inputValue) {
let splitStr = propertyString.split('.');
if (splitStr.length === 1) {
inputObject[splitStr[0]] = inputValue;
return;
}
else if (splitStr.length > 1) {
let newPropertyString = "";
let firstValue = splitStr.shift();
splitStr.forEach((subStr, i) => {
newPropertyString = i === 0 ? subStr : newPropertyString.concat(`.${subStr}`);
});
_setObjectValueByPathString(inputObject[firstValue], newPropertyString, inputValue);
return;
}
else {
throw "Invalid property string provided";
}
}
function _pushObjectValueByPathString(inputObject, propertyString, inputValue) {
let splitStr = propertyString.split('.');
if (splitStr.length === 1) {
inputObject[splitStr[0]].push(inputValue);
return;
}
else if (splitStr.length > 1) {
let newPropertyString = "";
let firstValue = splitStr.shift();
splitStr.forEach((subStr, i) => {
newPropertyString = i === 0 ? subStr : newPropertyString.concat(`.${subStr}`);
});
_pushObjectValueByPathString(inputObject[firstValue], newPropertyString, inputValue);
return;
}
else {
throw "Invalid property string provided";
}
}
function _pullObjectValueByPathString(inputObject, propertyString, inputValue) {
let splitStr = propertyString.split('.');
if (splitStr.length === 1) {
inputObject[splitStr[0]].pull(inputValue);
return;
}
else if (splitStr.length > 1) {
let newPropertyString = "";
let firstValue = splitStr.shift();
splitStr.forEach((subStr, i) => {
newPropertyString = i === 0 ? subStr : newPropertyString.concat(`.${subStr}`);
});
_pullObjectValueByPathString(inputObject[firstValue], newPropertyString, inputValue);
return;
}
else {
throw "Invalid property string provided";
}
}