so I'm using mongoDB for a migration project which takes queries as plain javascript/JSON:
queryObj = {}; // our main object I pass to mongodb for queries
The below code throws error
queryObj[inObj.row]['$eq'] = inObj.equals;
but this works....
queryObj[inObj.row[i]] = {};
queryObj[inObj.row]['$eq'] = inObj.equals;
Is there a easy way to make a object with many nested properties sans having to define them as object? I could make a constructor function but I assuming their is an easy in-built solution via Object.create.
The only way I can think of is to create a method that will create empty objects if needed.
/**
* Sets a deep property on an object by creating any required
* objects in the hierarchy that may not yet exist
* #param {object} obj The object to receive properties
* #param {string} prop Dot separated deep property to set
* #param {*} value What to set the given property to
*/
function setProp(obj, prop, value) {
var parts = prop.split('.');
var i = 0;
for (; i < parts.length - 1; i++) {
if (typeof obj[parts[i]] === 'undefined') {
obj[parts[i]] = {};
}
obj = obj[parts[i]];
}
// Note that parts[i] is pointing to the last part of the deep property name
// and obj points to the nested object that contains the last deep property
obj[parts[i]] = value
}
var obj = {}
setProp(obj, 'a.b.c', 3);
console.log(obj.a.b.c); // 3
For your case you could so something like
setProp( queryObj, inObj.row + ".$eq", inObj.equals );
Related
To initialize an Object array property and then push values seems to be a two step approach. Is there an optimal one line approach in ES6? Example of the issue is in the appendError(prop, error) method below.
Question:
Is there one line or more concise approach with JS or lodash?
Future optional chaining seems solve the problem, but is there a solution today? PHP allows $array[prop][] = val;
class Errors {
constructor(fields ) {
this.errors = {};
}
/**
* Clear one or all error fields.
*
* #param {string} prop | example: "email"
* #param {string} error | example: "Invalid email"
*/
appendError(prop, error) {
/* Set key and empty array if property doest exist */
if (!this.has(prop)) this.errors[prop] = [];
/* then Push value */
this.errors[prop].push(error);
}
/**
* Determine if an errors exists for the given field.
*
* #param {string} prop
*/
has(prop) {
return this.errors.hasOwnProperty(prop);
}
}
You can use Logical nullish assignment (??=) to assign an empty array, if the property value id undefined:
(this.errors[prop] ??= []).push(error);
Example:
class Errors {
constructor(fields) {
this.errors = {};
}
appendError(prop, error) {
(this.errors[prop] ??= []).push(error);
}
}
const errors = new Errors;
errors.appendError('a', 'a');
errors.appendError('a', 'b');
console.log(errors.errors);
You could abuse || for that:
this.errors[prop]?.push(error) || (this.errors[prop] = [error]);
You could write something like:
appendError(prop, error) {
(this.error[prop] = this.error[prop]||[]) && this.error[prop].push(error) && this.error[prop];
}
For example, I wish to create an object at the end of a nested chain of objects, eg:
window.a.b.c.d = {}
But I need to check if the parameters a, b, and c exist, else create them.
As far as I know, you need to do this:
window.a = window.a || {};
window.a.b = window.a.b || {};
window.a.b.c = window.a.b.c || {};
window.a.b.c.d = {};
Is there a faster/better ("one liner") method?
You can just write the object as below:
window.a = {
b: {
c: {
d: {
}
}
}
};
But when you want to make this on existent objects, it's better to write a function.
Example:
/**
* Create object(s) in a object.
*
* #param object obj
* #param array path
*/
function createObjectPath(obj, path) {
var currentPath = obj;
// Iterate objects in path
for(var i = 0, p; p = path[i]; i++) {
// Check if doesn't exist the object in current path
if(typeof currentPath[p] !== 'object') {
currentPath[p] = {};
}
currentPath = currentPath[p];
}
}
And you could use this function so:
createObjectPath(window, ['a', 'b', 'c', 'd']);
The function creates a reference of a argumented object in 1st parameter, then iterate over each string in the array argumented in the 2nd parameter and set each string as a object case doesn't exist in a parent object.
Lodash's set does exactly this in a one-liner (ignoring import)
import { set } from 'lodash'
set(window, 'a.b.c.d', {})
I have an object for a given verb such as...
var schlafen = {
ger: "schlafen",
eng: "sleep",
stem: "schlaf",
pp: "geschlafen",
sp: "schlief",
type: "verb",
reflexive: false
};
I would like to be able to identify and reference the object and it's properties when my script comes across an instance of one of it's properties such as...
var example = "geschlafen";
I am trying to get to the object itself from only one of it's properties so that I can then use another one of it's properties(for example, the "type" property) to identify an instance of "geschlafen" as a verb.
One option would be to create an index object that maps the values back to the associated object, for example:
var index = {};
function indexObject(obj) {
var keys = ['ger', 'eng', 'stem', 'pp', 'sp'];
for (var i = 0; i < keys.length; i++) {
if (obj[keys[i]]) {
index[obj[keys[i]]] = obj;
}
}
}
// index your schlafen object (you would also want to do this for other objects)
indexObject(schlafen);
var example = "geschlafen";
// lookup the object using your index
var obj = index[example];
// make sure we got the correct object back (should log 'true')
console.log(obj === schlafen);
I want to create an Object that contains one or more two dimensional arrays in Javascript.
I tried it the following way (in this example I only try to add one two dimensional array):
var XSIZE = 8;
var YSIZE = 8;
var obj = {
field : new Array(XSIZE),
field[0] : new Array(YSIZE),
foo : 1,
bar : 100
}
Info:
- This gives me a strange error "missing : after property id" which does not seem to make much sense
- Unfortunately I didn't find examples showing how to do this so far by using google
- If I don't add field[0] ... for creating the 2nd array it works.
- changing the XSIZE and YSIZE to numbers like new Array(8)... doesn't work.
I would really appreciate if somebody could show me how to do it or explain why I cannot do this at all and need to use some other method.
Thanks a lot!
The error "missing : after property id" is because JavaScript sees the field part of field[0] and expects a colon before the value of that field. Instead it gets an open bracket so it complains.
You can't hard code an object definition that has its dimensions set up at run time. You have to build the object at run time as well. Like this perhaps
var XSIZE = 8;
var YSIZE = 8;
var obj = {
field : new Array(),
foo : 1,
bar : 100
}
for (var i = 0; i < XSIZE; i++) {
obj.field.push(new Array(YSIZE));
}
In object literal notation, the property names must be exactly that: property names. Firstly, field[0] isn't a property name. Secondly, the properties don't exist until the after the object defined, so you can't access properties until then.
What you should do is either set the array after the object is created:
var obj = {...}
obj.field[0] = [...];
or nest the array literals:
var obj = {
field: [ [...],
...
],
...
}
You don't need to worry about setting the array size when creating the array, as it will grow when you add elements.
You can only declare properties on the object being constructed that way; not on objects in another "level".
You could use a for loop instead:
for(var i = 0; i < XSIZE; i++) {
obj.field[i] = new Array(YSIZE);
}
Note that the YSIZE is not necessary since an empty array works just fine as well ([]).
You could get the two dimensional array as your obj property, without resorting to external procedures and keep everything internal to the object. Create your empty 'field' array 1st.
var obj = {
field:[],
foo:1,
bar:100
};
Now, create an object's method to create a two dimensional array off your initial dimensionless array. You can determine the length and the number of dimensions of multi dimension array as you wish at run time:
var obj = {
field:[],
multifield:function(x,y){for (var count=0;count<x;count++) {this.field[count]=new Array(y);}},
foo:1,
bar:100
};
You can then call the obj.multifield method entering whatever dimensions you decide:
obj.multifield(10,5); //-->create a 10x5 array in this case...
console.log(obj.field.length); // 10
console.log(obj.field[0].length); // 5
How can I inspect an Object in an alert box? Normally alerting an Object just throws the nodename:
alert(document);
But I want to get the properties and methods of the object in the alert box. How can I achieve this functionality, if possible? Or are there any other suggestions?
Particularly, I am seeking a solution for a production environment where console.log and Firebug are not available.
How about alert(JSON.stringify(object)) with a modern browser?
In case of TypeError: Converting circular structure to JSON, here are more options: How to serialize DOM node to JSON even if there are circular references?
The documentation: JSON.stringify() provides info on formatting or prettifying the output.
The for-in loops for each property in an object or array. You can use this property to get to the value as well as change it.
Note: Private properties are not available for inspection, unless you use a "spy"; basically, you override the object and write some code which does a for-in loop inside the object's context.
For in looks like:
for (var property in object) loop();
Some sample code:
function xinspect(o,i){
if(typeof i=='undefined')i='';
if(i.length>50)return '[MAX ITERATIONS]';
var r=[];
for(var p in o){
var t=typeof o[p];
r.push(i+'"'+p+'" ('+t+') => '+(t=='object' ? 'object:'+xinspect(o[p],i+' ') : o[p]+''));
}
return r.join(i+'\n');
}
// example of use:
alert(xinspect(document));
Edit: Some time ago, I wrote my own inspector, if you're interested, I'm happy to share.
Edit 2: Well, I wrote one up anyway.
Use console.dir(object) and the Firebug plugin
There are few methods :
1. typeof tells you which one of the 6 javascript types is the object.
2. instanceof tells you if the object is an instance of another object.
3. List properties with for(var k in obj)
4. Object.getOwnPropertyNames( anObjectToInspect )
5. Object.getPrototypeOf( anObject )
6. anObject.hasOwnProperty(aProperty)
In a console context, sometimes the .constructor or .prototype maybe useful:
console.log(anObject.constructor );
console.log(anObject.prototype ) ;
Use your console:
console.log(object);
Or if you are inspecting html dom elements use console.dir(object). Example:
let element = document.getElementById('alertBoxContainer');
console.dir(element);
Or if you have an array of js objects you could use:
console.table(objectArr);
If you are outputting a lot of console.log(objects) you can also write
console.log({ objectName1 });
console.log({ objectName2 });
This will help you label the objects written to console.
var str = "";
for(var k in obj)
if (obj.hasOwnProperty(k)) //omit this test if you want to see built-in properties
str += k + " = " + obj[k] + "\n";
alert(str);
This is blatant rip-off of Christian's excellent answer. I've just made it a bit more readable:
/**
* objectInspector digs through a Javascript object
* to display all its properties
*
* #param object - a Javascript object to inspect
* #param result - a string of properties with datatypes
*
* #return result - the concatenated description of all object properties
*/
function objectInspector(object, result) {
if (typeof object != "object")
return "Invalid object";
if (typeof result == "undefined")
result = '';
if (result.length > 50)
return "[RECURSION TOO DEEP. ABORTING.]";
var rows = [];
for (var property in object) {
var datatype = typeof object[property];
var tempDescription = result+'"'+property+'"';
tempDescription += ' ('+datatype+') => ';
if (datatype == "object")
tempDescription += 'object: '+objectInspector(object[property],result+' ');
else
tempDescription += object[property];
rows.push(tempDescription);
}//Close for
return rows.join(result+"\n");
}//End objectInspector
Here is my object inspector that is more readable. Because the code takes to long to write down here you can download it at http://etto-aa-js.googlecode.com/svn/trunk/inspector.js
Use like this :
document.write(inspect(object));