JavaScript Dynamic naming with argument of function. - javascript

I have been looking around for an answer to this but in vain.
I have a function which takes a table name as an argument. but this name can be an object.
loadDataFromServer = function(dataTable) {
//data fetch code ...
datadump[dataTable] = response.getDataTable();
}
loadDataFromServer(['gchart']['data'])
The problem is I need to store the data in a variable datadump.gchart.data but the "gchart.data" part needs to be determined upon calling the function, not hard coded in it.
my problem lies in the fact that
datadump[['gchart']['data']] is not the same as
datadump['gchart']['data'] (which is the same as datadump.gchart.data)
Does anybody here know a good way to do this? If the input was simply gchart_data, this would easily work, but the functions needs to able to handle it even if it needed to assign its data to blabla.blibli.bloebloe.stuff.
thanks in advance

I think what you're looking for is this:
function (result) {
datadump = {};
datadump.gchart = {};
datadump.gchart.data = result.gchart.data;
// or
datadump.gchart = {
data: result.gchart.data
};
}
It's a little bit strange to it like this though. Do you absolutely need the gchart in your datadump?
Assigning to a random depth like blabla.blibli.bloebloe.stuff is not easily done.
You could flatten like: obj["blabla.blibli.bloebloe.stuff"] = {};
Or you could write a recursive merge, like:
var a, b, c;
a = { foo: { ipsum: "lorem" } };
b = { bar: {}, foo: { abc: "def" } };
c = recursive_merge(a, b); // { foo: { ipsum: "lorem", abc: "def" }, bar: {} };

Have you function take a list of strings and iterate over them to recursively access (and, if necessary, create) properties of datadump. I use arguments here to use the list of arguments itself, but you could also just use a single argument that is an array of strings.
var loadDataFromServer = function() {
var currObj = datadump;
// iterate over the list of property names
for(var i=0; i<arguments.length - 1; ++i) {
var nextName = arguments[i];
// if the object doesn't have this property, make it
if(currObj[nextName] == undefined) {
currObj[nextName] = {};
}
// use currObj's property as the new `currObj`
currObj = currObj[nextName];
}
// load data into the final named property
currObj[arguments[i]] = response.getDataTable();
}
loadDataFromServer('gchart', 'data');

Related

Object literal with nested function as prototype of data Object

I'm creating a GAS Spreadsheets Service based app that reads/writes & updates a row of data. I have a key-value object that represents a row of data, like the example data provided in snippet.
Use case:
var exampleData = [{weekendVolume=5186270,midweekVolume=16405609}];
// tuple length 2 of two known values
function _DataRecordObject( exampleData ) {
this._endOfWeek = new Date().endOfWeek();// Date.prototype method
}
var _DataRecordMethods = {
weekEnding: function() {
return this._endOfWeek.formatDateString()
},
weekMonth: function() {
return this._endOfWeek.getMonthLabelShort()
},
/* Processed volume */
weekendVolume: function() {
return 'weekendVolume'
},
midweekVolume: function() {
return 'midweekVolume'
},
totalVolumeProcessed: function() {
return _SumTotal(
this.weekendVolume(),
this.midweekVolume()
)
}
}
_DataRecordObject.prototype = _DataRecordMethods;
The new DataRecordObject is prototype of a Sheet object that provides other helpful properties. _SumTotal is a helper function.
My question:
When I call a new DataRecordObject with sheet range as argument, how do I update the exampleData object with the new properties such as totalVolumeProcessed?
For example:
var foo = new _DataRecordObject( exampleData );
Console.log( foo );
//[{weekEnding='Aug-17',weekMonth=4,weekendVolume=5186270,midweekVolume=16405609,totalVolumeProcessed=21591879}]
I'd like the flexibility of using constructor-prototype inheritence, but using a boilerplate style template like Object-literals. My intuition suggests that I need to pass the data object keys when constructing a new dataRecordObject.
I'm a newcomer to JavaScript and have not yet gotten my head around inheritance, prototypes, and respective design-patterns. Factories and Modules, or perhaps Observers seem like appropriate patterns but my limited experience with JS is a limiting factor to solving my problem.
This might work for you.
1) Define the prototype as an object literal:
var methods = {
sayName: function() {
return "My name is " + this.name;
},
sayAge: function() {
return "I am " + this.age + " years old";
}
};
2) You can either make the 'methods' variable global or define it inside the following function. The function creates a new object using 'methods' variable as a prototype and populates it with values from the 'data' argument.
function createNewObj (data) {
var data = data || null;
var result = Object.create(methods);
for (var key in data) {
if (data.hasOwnProperty(key)) {
result[key] = data[key];
}
}
return result;
}
3) Bringing things together
function test() {
var data = {name: "John", age: "32"};
var row = createNewObj(data);
Logger.log(row.name); //logs 'John'
Logger.log(row.age); //logs '32'
Logger.log(row.sayName()); //logs 'My name is John'
Logger.log(row.sayAge()); //logs 'I am 32 years old'
Logger.log(Object.getPrototypeOf(row)); // returns contents of the 'methods' object literal
Logger.log(row.hasOwnProperty("sayName")); //logs 'false' because 'hasOwnProperty' doesn't go up the prototype chain
Logger.log("sayName" in row); //logs 'true' because 'in' goes up the chain
}
I suggest you take a look at this blog post by Yehuda Katz that dives deeper into prototypes http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/ It has examples of much cleaner code that might be helpful.
I've found a solution, which expands on #Anton-Dementiev 's response. His suggestion to read the Yehudi Katz was also most helpful.
The create new object function, _DataRecordObject is where the solution lies..
function _DataRecordObject( RowDataObject ) {
this._endOfWeek = new Date().endOfWeek();// Date.prototype method
var data = RowDataObject || null;
var result = Object.create( _DataRecordMethods );
for (var key in data) {
if ( data.hasOwnProperty( key ) ) {
// if value is present in the RowDataObject,
// then assign its value to the result
result[key] = data[key];
} else {
// if not, the value is a method function,
// which should be evaluated in that context,
// and then return the method value as result
var foo = Object.getPrototypeOf( result )[ key ];
result[key] = foo.call( data );
}
}
return result;
}
//simples
Since the methods are passed as property functions, they need to be called as functions in that context.

new vs object create giving different results OO javascript

I'm working with a data object lit, then trying to create a new object that changes properties in the data property just for that instance, here's some test code from jsbin
data = {
innerData : 1
}
-------------
'This works :-)'
construct = function(d){
this.data = Object.create(d);
};
construct.prototype.c = function(n){
this.data.innerData = n;
};
construct.prototype.d = function(){
console.log(this.data.innerData)
};
--------------
'This does not :-{'
construct = {
data : Object.create(data),
changeData : function(n){
this.data.innerData = n;
},
showData:function(){
console.log(this.data.innerData)
}
}
--------------
newInst = Object.create(construct);
newInst.changeData(5);
newInst.showData();
newInst2 = Object.create(construct);
newInst2showData();
when I run it using the constructor/prototype functions it works and the console outputs 5,2
when I run it using the object literal the console outputs 5,5 I guess when I create the first instance it changes the actual data object and not the data property of the instance of the construct object.
If someone could explain in depth why this happens that would be much help as I've not been working with OOJS for that long
UPDATE:
so I had a little go at merging what I found useful from the answers and I've come up with this....
data = {
innerData : 1
}
function construct(d){
return {
data : Object.create(d),
changeData : function(n){
this.data.innerData = n;
},
showData : function(){
console.log(this.data.innerData)
}
}
}
build = function(){
return(new construct(data));
}
newInst = build();
newInst.changeData(5);
newInst.showData();
newInst2 = build();
newInst2.showData();
Given what we know about the inheritance, what does the following actually do
this.data.innerData = n;
where this is the result of Object.create(construct)?
this does not have own property data, so look up in the inherited properties.
Okay we found a data === Object.getPrototypeOf(this).data, call it d
Next set innerData of d to n
So what the actual result has ended up is the innerData property has been set on the reference from the prototype, and not a new Object.
Why has this happened? Because if you have o = {} and try to do o.foo.bar, you get a TypeError: Cannot read property 'bar' of undefined, and therefore for it to not throw an error, it has to be accessing a defined Object.
var proto = {foo: {bar: 'fizz'}},
obj = Object.create(proto);
obj.foo.bar = 'buzz';
proto.foo.bar; // "buzz" (i.e. NOT "fizz" anymore)
// and
obj.foo === Object.getPrototypeOf(obj).foo; // true
In your second example, there is only ever one data object. That object lives inside construct and is available to all the subsequent objects on the prototype chain.
In your first example, you make a new data object every time a new instance is created. So each object gets its own copy of data.
Try this, for the first example:
console.log(newInst.data === newInst2.data); // should be false
and for the second example:
console.log(newInst.data === newInst2.data); // should be true
The second piece of code works just fine:
construct.changeData(2);
construct.showData(); // 2
The only difference is that in the above example construct is not a constructor, so there will be only a single instance of construct.data as opposed to the first approach; calling Object.create() on it will create a new object but will keep the same .data reference as the first.
This looks like an attempt to create a factory function instead of a constructor function. Since Object.create is now widespread, and shimmable for these purposes where not available, this has become perhaps the best default, although there are plenty of constructor functions still around.
Some of the other answers explain what went wrong with your attempt. Here's how you might do it so that it works as expected:
var factory = (function() {
var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
var data = {
innerData : 1
};
var proto = {
changeData : function(n){
this.data.innerData = n;
},
showData:function(){
console.log(this.data.innerData)
}
};
return function() {
var obj = Object.create(proto);
obj.data = clone(data);
return obj;
}
}());
But it looks as though your innerData might have been an experiment to try to get these things working. It it's not necessary, this would be cleaner:
var factory = (function() {
var proto = {
data: 1,
changeData : function(n){
this.data = n;
},
showData:function(){
console.log(this.data)
}
};
return function() {
return Object.create(proto);
}
}());

Array subclass prototype sort

I'm curious how to go about implementing my own sort function on the Array object. Ignoring all the usual warnings/dangers about extending/overriding a built-in, consider this:
Array.prototype.sort = function() {
this = mySortFunction(this);
function mySortFunction(arr) { ... };
};
Inside the closure, this refers to the Array object [number, number2, number3, etc.]. How do I go about reassigning this to be the result of my internal sorting function? Is it possible?
Your solution seems a little redundant:
Array.prototype.sort = function() {
this = mySortFunction(this);
function mySortFunction(arr) {
arr = yetAnotherSortFunction(arr)
function yetAnotherSortFunction(arr2) {...}
// and so on...
};
};
If you really want to do it this way, why not reference your array directly in the first place:
Array.prototype.sort = function() {
// your implementation:
// for (var i = this.length, ...
// if (this[0] == ...
// this[i] = ...
// ...
};

Javascript objects: get parent [duplicate]

This question already has answers here:
access parent object in javascript
(15 answers)
Closed 5 years ago.
I have the following (nested) object:
obj: { subObj: { foo: 'hello world' } };
Next thing I do is to reference the subobject like this:
var s = obj.subObj;
Now what I would like to do is to get a reference to the object obj out of the variable s.
Something like:
var o = s.parent;
Is this somehow possible?
A nested object (child) inside another object (parent) cannot get data directly from its parent.
Have a look on this:
var main = {
name : "main object",
child : {
name : "child object"
}
};
If you ask the main object what its child name is (main.child.name) you will get it.
Instead you cannot do it vice versa because the child doesn't know who its parent is.
(You can get main.name but you won't get main.child.parent.name).
By the way, a function could be useful to solve this clue.
Let's extend the code above:
var main = {
name : "main object",
child : {
name : "child object"
},
init : function() {
this.child.parent = this;
delete this.init;
return this;
}
}.init();
Inside the init function you can get the parent object simply calling this.
So we define the parent property directly inside the child object.
Then (optionally) we can remove the init method.
Finally we give the main object back as output from the init function.
If you try to get main.child.parent.name now you will get it right.
It is a little bit tricky but it works fine.
No. There is no way of knowing which object it came from.
s and obj.subObj both simply have references to the same object.
You could also do:
var obj = { subObj: {foo: 'hello world'} };
var obj2 = {};
obj2.subObj = obj.subObj;
var s = obj.subObj;
You now have three references, obj.subObj, obj2.subObj, and s, to the same object. None of them is special.
This is an old question but as I came across it looking for an answer I thought I will add my answer to this to help others as soon as they got the same problem.
I have a structure like this:
var structure = {
"root":{
"name":"Main Level",
nodes:{
"node1":{
"name":"Node 1"
},
"node2":{
"name":"Node 2"
},
"node3":{
"name":"Node 3"
}
}
}
}
Currently, by referencing one of the sub nodes I don't know how to get the parent node with it's name value "Main Level".
Now I introduce a recursive function that travels the structure and adds a parent attribute to each node object and fills it with its parent like so.
var setParent = function(o){
if(o.nodes != undefined){
for(n in o.nodes){
o.nodes[n].parent = o;
setParent(o.nodes[n]);
}
}
}
Then I just call that function and can now get the parent of the current node in this object tree.
setParent(structure.root);
If I now have a reference to the seconds sub node of root, I can just call.
var node2 = structure.root.nodes["node2"];
console.log(node2.parent.name);
and it will output "Main Level".
Hope this helps..
Many of the answers here involve looping through an object and "manually" (albeit programmatically) creating a parent property that stores the reference to the parent. The two ways of implementing this seem to be...
Use an init function to loop through at the time the nested object is created, or...
Supply the nested object to a function that fills out the parent property
Both approaches have the same issue...
How do you maintain parents as the nested object grows/changes??
If I add a new sub-sub-object, how does it get its parent property filled? If you're (1) using an init function, the initialization is already done and over, so you'd have to (2) pass the object through a function to search for new children and add the appropriate parent property.
Using ES6 Proxy to add parent whenever an object/sub-object is set
The approach below is to create a handler for a proxy always adds a parent property each time an object is set. I've called this handler the parenter handler. The parenter responsibilities are to recognize when an object is being set and then to...
Create a dummy proxy with the appropriate parent and the parenter handler
var p = new Proxy({parent: target}, parenter);
Copy in the supplied objects properties-- Because you're setting the proxy properties in this loop the parenter handler is working recursively; nested objects are given parents at each level
for(key in value){
p[key] = value[key];
}
Set the proxy not the supplied object
return target[prop] = p;
Full code
var parenter = {
set: function(target, prop, value){
if(typeof value === "object"){
var p = new Proxy({parent: target}, parenter);
for(key in value){
p[key] = value[key];
}
return target[prop] = p;
}else{
target[prop] = value;
}
}
}
var root = new Proxy({}, parenter);
// some examples
root.child1 = {
color: "red",
value: 10,
otherObj: {
otherColor: "blue",
otherValue: 20
}
}
// parents exist/behave as expected
console.log(root.child1.color) // "red"
console.log(root.child1.otherObj.parent.color) // "red"
// new children automatically have correct parent
root.child2 = {color: "green", value3: 50};
console.log(root.child2.parent.child1.color) // "red"
// changes are detected throughout
root.child1.color = "yellow"
console.log(root.child2.parent.child1.color) // "yellow"
Notice that all root children always have parent properties, even children that are added later.
There is a more 'smooth' solution for this :)
var Foo = function(){
this.par = 3;
this.sub = new(function(t){ //using virtual function to create sub object and pass parent object via 't'
this.p = t;
this.subFunction = function(){
alert(this.p.par);
}
})(this);
}
var myObj = new Foo();
myObj.sub.subFunction() // will popup 3;
myObj.par = 5;
myObj.sub.subFunction() // will popup 5;
To further iterate on Mik's answer, you could also recursivey attach a parent to all nested objects.
var myApp = {
init: function() {
for (var i in this) {
if (typeof this[i] == 'object') {
this[i].init = this.init;
this[i].init();
this[i].parent = this;
}
}
return this;
},
obj1: {
obj2: {
notify: function() {
console.log(this.parent.parent.obj3.msg);
}
}
},
obj3: {
msg: 'Hello'
}
}.init();
myApp.obj1.obj2.notify();
http://jsbin.com/zupepelaciya/1/watch?js,console
You could try this(this uses a constructor, but I'm sure you can change it around a bit):
function Obj() {
this.subObj = {
// code
}
this.subObj.parent = this;
}
I have been working on a solution to finding the parent object of the current object for my own pet project. Adding a reference to the parent object within the current object creates a cyclic relationship between the two objects.
Consider -
var obj = {
innerObj: {},
setParent: function(){
this.innerObj.parent = this;
}
};
obj.setParent();
The variable obj will now look like this -
obj.innerObj.parent.innerObj.parent.innerObj...
This is not good. The only solution that I have found so far is to create a function which iterates over all the properties of the outermost Object until a match is found for the current Object and then that Object is returned.
Example -
var obj = {
innerObj: {
innerInnerObj: {}
}
};
var o = obj.innerObj.innerInnerObj,
found = false;
var getParent = function (currObj, parObj) {
for(var x in parObj){
if(parObj.hasOwnProperty(x)){
if(parObj[x] === currObj){
found = parObj;
}else if(typeof parObj[x] === 'object'){
getParent(currObj, parObj[x]);
}
}
}
return found;
};
var res = getParent(o, obj); // res = obj.innerObj
Of course, without knowing or having a reference to the outermost object, there is no way to do this. This is not a practical nor is it an efficient solution. I am going to continue to work on this and hopefully find a good answer for this problem.
Try this until a non-no answer appears:
function parent() {
this.child;
interestingProperty = "5";
...
}
function child() {
this.parent;
...
}
a = new parent();
a.child = new child();
a.child.parent = a; // this gives the child a reference to its parent
alert(a.interestingProperty+" === "+a.child.parent.interestingProperty);
You will need the child to store the parents this variable. As the Parent is the only object that has access to it's this variable it will also need a function that places the this variable into the child's that variable, something like this.
var Parent = {
Child : {
that : {},
},
init : function(){
this.Child.that = this;
}
}
To test this out try to run this in Firefox's Scratchpad, it worked for me.
var Parent = {
data : "Parent Data",
Child : {
that : {},
data : "Child Data",
display : function(){
console.log(this.data);
console.log(this.that.data);
}
},
init : function(){
this.Child.that = this;
}
}
Parent.init();
Parent.Child.display();
Just in keeping the parent value in child attribute
var Foo = function(){
this.val= 4;
this.test={};
this.test.val=6;
this.test.par=this;
}
var myObj = new Foo();
alert(myObj.val);
alert(myObj.test.val);
alert(myObj.test.par.val);
when I load in a json object I usually setup the relationships by iterating through the object arrays like this:
for (var i = 0; i < some.json.objectarray.length; i++) {
var p = some.json.objectarray[i];
for (var j = 0; j < p.somechildarray.length; j++) {
p.somechildarray[j].parent = p;
}
}
then you can access the parent object of some object in the somechildarray by using .parent

JavaScript Object Id

Do JavaScript objects/variables have some sort of unique identifier? Like Ruby has object_id. I don't mean the DOM id attribute, but rather some sort of memory address of some kind.
If you want to lookup/associate an object with a unique identifier without modifying the underlying object, you can use a WeakMap:
// Note that object must be an object or array,
// NOT a primitive value like string, number, etc.
var objIdMap=new WeakMap, objectCount = 0;
function objectId(object){
if (!objIdMap.has(object)) objIdMap.set(object,++objectCount);
return objIdMap.get(object);
}
var o1={}, o2={}, o3={a:1}, o4={a:1};
console.log( objectId(o1) ) // 1
console.log( objectId(o2) ) // 2
console.log( objectId(o1) ) // 1
console.log( objectId(o3) ) // 3
console.log( objectId(o4) ) // 4
console.log( objectId(o3) ) // 3
Using a WeakMap instead of Map ensures that the objects can still be garbage-collected.
No, objects don't have a built in identifier, though you can add one by modifying the object prototype. Here's an example of how you might do that:
(function() {
var id = 0;
function generateId() { return id++; };
Object.prototype.id = function() {
var newId = generateId();
this.id = function() { return newId; };
return newId;
};
})();
That said, in general modifying the object prototype is considered very bad practice. I would instead recommend that you manually assign an id to objects as needed or use a touch function as others have suggested.
Actually, you don't need to modify the object prototype. The following should work to 'obtain' unique ids for any object, efficiently enough.
var __next_objid=1;
function objectId(obj) {
if (obj==null) return null;
if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
return obj.__obj_id;
}
I've just come across this, and thought I'd add my thoughts. As others have suggested, I'd recommend manually adding IDs, but if you really want something close to what you've described, you could use this:
var objectId = (function () {
var allObjects = [];
var f = function(obj) {
if (allObjects.indexOf(obj) === -1) {
allObjects.push(obj);
}
return allObjects.indexOf(obj);
}
f.clear = function() {
allObjects = [];
};
return f;
})();
You can get any object's ID by calling objectId(obj). Then if you want the id to be a property of the object, you can either extend the prototype:
Object.prototype.id = function () {
return objectId(this);
}
or you can manually add an ID to each object by adding a similar function as a method.
The major caveat is that this will prevent the garbage collector from destroying objects when they drop out of scope... they will never drop out of the scope of the allObjects array, so you might find memory leaks are an issue. If your set on using this method, you should do so for debugging purpose only. When needed, you can do objectId.clear() to clear the allObjects and let the GC do its job (but from that point the object ids will all be reset).
const log = console.log;
function* generateId() {
for(let i = 0; ; ++i) {
yield i;
}
}
const idGenerator = generateId();
const ObjectWithId = new Proxy(Object, {
construct(target, args) {
const instance = Reflect.construct(target, args);
instance['id'] = idGenerator.next().value;
return instance;
}
})
const myObject = new ObjectWithId({
name: '##NativeObject'
});
log(myObject.id);

Categories