In Swift we have #dynamicMemberlookup which lets us dynamically reference a property without having to first define it. Great for situations where keys names on things like maps are not known in advance. For example I can do something like this:
object.abc = 5
object.abc // -> 5
And the compiler will call a pre-defined function:
subscript(dynamicMember member: String) -> Int {
get { return someMap[member] }
set { someMap[member] = newValue
}
Effectively it's syntactical sugar. But what I'm doing at the moment is calling some user supplied Javascript from my Swift app and as part of that call I'm passing an object to the javascript which can be used to get and retrieve values.
At the moment I've defined function get(key) {...} and function set(key, value) {...} functions on the object I'm passing. This allows:
object.set("abc", 5);
object.get("abc"); // -> 5
But I'd really like the javascript to be able to do a dynamic property without knowing the name of it in advance. ie:
object.abc = 5;
object.abc; // -> 5
I've looked around but I can't see if this is possible in Javascript. Is it?
Edit
ultimately the object I pass to the javascript is a Swift object and the get and set functions I defined in the javascript are actually routing to the backing Swift object in a dynamic manner. That means that when I call the javascript I don't have to pass every single value currently stored. Which could be a large amount.
Not sure I follow you but is this what you want ?
let propName = 'abc' ;
object[propName] = 5
console.log(object[propName]) ;
you can change the property name to anything you want and it will just create, set and retrieve that property
Related
A little background on the problem
I've built a custom system to automatically watch some "store" properties that comes from a JSON of a nosql database. Nothing too complicated except the nesting (required for several reasons not discussed here) of objects.
The data structure looks like this:
{
store: {
objA: {
objB: {
prop1: 'some value'
}
}
}
}
However, since it's a nosql database that provide that store property, objB can just be NOT present after the load from the database.
Example of the template used
I have custom components that have props bound directly to that data store
<my-selector :value.sync="store.objA.objB.prop1">
</my-selector>
However, it crashes when "objB" is not present with the usual javascript error saying that it cannot get "objB" of undefined, but that is normal.
I'm trying to find a vuejs way to prepare the data for me.
Ideas
In order to counter that crash :
I can NOT use v-if in that case to mask the selector. Because that selector can be used even if the data is not yet set (example: for optional data).
I could fix the "load" function that gets the data from the database so it initialize the required properties (like objB) before assigning data to the data store. However, that would imply that my initial VueJS data object would contain these required properties as well. It's probably that I will use if I can't find any alternative solution, but I don't think that's the easiest way around because I would have to fix any incoming data before assignment.
My preferred choice would be to create a directive (or any other thing built in the template) that would add them for me if they are missing.
VueJS always evaluates the bindings value
I thought of that solution:
<my-selector v-autocreate="'store.objA.objB.prop1'" :value.sync="store.objA.objB.prop1">
</my-selector>
However the directive binding "v-autocreate" is not picked up first (checked with the debugger).
I did not find documentation relative of the order of load of directives or attributes.
I was also hoping to get all bindings of a node with the directive "bind"
function in order to NOT repeat the string, but it seems we can't get that information (I'm used to knockoutjs where we can pick all bindings assigned to a node in order to behave differently).
I would like to reach that goal but I'm not sure that it's possible (I would need something like a pre-bind / beforeBind event on directive haha) :
<my-selector v-autocreate :value.sync="store.objA.objB.prop1">
</my-selector>
Where v-autocreate would assure to do the vm.$set of the missing properties.
You could create a method that checks each property in an object path, creates it if it doesn't exist, then returns the value of the last property.
Example (not tested):
get(object, path) {
path = path.split('.')
let index = 0
const length = path.length
let val
while (object != null && index < length) {
let key = path[index++]
if(object[key] == null) {
this.$set(object, key, {})
}
object = object[key]
}
return val
}
Usage:
<my-selector :value="get(store,'objA.objB.prop1')">
</my-selector>
You may be interested in lodash's get function, which is what the code example is based on.
https://github.com/lodash/lodash/blob/master/get.js
I would like to find out if it is possible to get all properties of a class having an object that is created as an instance of this class.
The thing is that I'm trying to create a generic admin page for any entity that it is bound to. I use TypeORM and I managed to fetch required entity repository from which I am able to get an instance of entity object(s).
Now, how can I get the class of this generic entity to iterate over its properties? I need it to create input fields on the view-side. This is not a problem when I process existing entities (at least when I have all the data filled in for them) but it is a bit of a challenge when trying to create a new entity, as the instance I get is a pristine empty object and trying to console.dir it returns something like City {}.
Here is some basic code on the subject:
public static build(req: Request, res: Response, entityRepository: Repository<any>, args: any) {
// ...
if (args.action === 'create') {
const targetEntity: Function = <Function> entityRepository.target();
let entity = entityRepository.create();
// Now I need to get the class of this entity to
//pass it to the view that will display input fields accordingly
console.dir(Object.getPrototypeOf(entity)); // Output: City {}
// ...
}
}
UPDATE
I would paraphrase my question.
I came across the fact that I can obtain the class of the object, but I do not get its properties if they are not defined. E.g.:
class Foo {
bar: any;
}
Getting own properties on this class returns [].
But:
class Foo {
bar: any = "";
}
This will return ['bar'].
So, how can I get CLASS property names instead of OBJECT property names even when their values are not defined? I'd prefer to avoid defining every single property on every entity with dummy value like '' and 0.
I'd prefer to avoid defining every single property on every entity with dummy value like '' and 0.
Such dummy values actually help optimize the Machine code generated by JIT compilers in JavaScript runtimes.
More importantly you can't get the key names as the generate JavaScript doesn't have introspection features to assist in this case.
An alternative is to try instanceof but that only tells the type of the class ... not its properties.
i'm reading the book 'Secrets of the JavaScript Ninja' (http://jsninja.com/) and wonder why a certain code block from one of the examples is coded like it is.
The example (http://jsfiddle.net/3s5bopqe/3/) builds a custom array type (MyArray) and reuses a number of functions from the Array.prototype without actually inheriting from the 'Array' type.
In the example from the book a function with a certain name is reused in the prototype of the custom type using this code
MyArray.prototype[ name ] = function() {
return Array.prototype[ name ].apply(this, arguments);
};
I believe i understand what happens here. But it seems unnecessary to me to actually use a function literal and explicitly 'apply' a function from the Array.prototype. The following code works just as well in the test setting :
MyArray.prototype[ name ] = Array.prototype[ name ];
My question is whether there are any advantages of using the code from the book over the last code block ?
By using
MyArray.prototype[ name ] = Array.prototype[ name ];
you are actually copying method from Array into your object (MyArray).
In future, if Array method changes, your MyArray method wont be updated.
By using
MyArray.prototype[ name ] = function() {
return Array.prototype[ name ].apply(this, arguments);
};
you referred to Array method. Changes made in Array object methods are reflected in your MyArray methods. Why? Because you never copied that method, you just borrowed it (referred to its current implementation).
There's one major difference I can see. If any of the targeted methods on Array.prototype gets altered after you copied them (e.g. applying a polyfill that fixes behavior) the changes will not be reflected using MyArray.prototype[ name ] = Array.prototype[ name ]; while it would using the jsninja approach.
Depending on your point of view, you may find one or the other behavior more fitting.
I have a variable called jsonAllSignOffs that is created by a .NET JSON service and sent to the client. It is essentially a struct containing various arrays. The values of these arrays are arranged such that if you took the nth element of each array, all together that would be the collected properties of the nth Sign Off. Obviously a list of Sign Off objects containing these properties would be better, but unfortunately this is a legacy application and changing it's architecture in this manner is out of scope.
What I'm trying to do is create a variable called jsonUserSignOffs that is essentially a subset of jsonAllSignOffs with all the same properties. However jsonAllSignOffs is not a type that I can instantiate. I figured declaring a variable and assuming the properties by assigning into them would "build" the object, but apparently that's not the case.
var jsonUserSignOffs;
jsonUserSignOffs.isAuthor = jsonAllSignOffs.isAuthor; //error jsonUserSignOffs is undefined
Since javascript doesn't support classes and is pretty lax with variables I figured the only way to create a struct like jsonAllSignOffs was to declare the variable and assign values to it's properties. I know these properties are not defined anywhere, but I thought assigning values to them would instantiate them at the same time. I come from a C# background where I would use a class. Javascript is less familiar to me, and I'm unclear on how to proceed.
Try this
var jsonUserSignOffs = {}; //creates an empty object using object literal notation
jsonUserSignOffs.isAuthor = jsonAllSignOffs.isAuthor;
OR:
var jsonUserSignOffs = {
isAuthor: jsonAllSignOffs.isAuthor
};
I'd really like to track variables without switching between Firebug console windows or clicking around so much, so I want to draw a runtime viewer of variable names and their corresponding values that will display on the page of the app I am building.
I'd like to two functions, show(variableName) and freeze(variableName). They will output both the variable's value and the name of the variable or object as a literal string which will serve as the text label in the viewer. freeze(variableName) is the same as show(variableName) except with a setTimeOut timer for tracking loops.
I'm sure I'm missing something basic, but I haven't found out a way to get the string that comprises the name of a value programmatically so I can use it as a label. I guess I could create the table with hardcoded labels prior to runtime and just populate it with values at runtime, but I really want to generate the table dynamically so it only has those variables I specifically want to show or freeze. Simple functions:
foo1 = "Rock";
show(foo1);
foo2 = "Paper";
show(foo2);
foo3 = "Scissors";
show(foo3);
should output this via getElementById('viewer-table'):
<table>\<tr><td>foo1</td><td>Rock</td></tr><tr><td>foo2</td><td>Paper</td></tr><tr><td>foo3</td><td>Scissors</td></tr></table>
I've tried this solution:
How to convert variable name to string in JavaScript?
and eval() but it's not working for me...I dunno, shouldn't this be easy? Getting frustrated...
Thanks,
motorhobo
I am not sure you can actually get the "name" of the variable that is being passed into a function for two reasons:
1) The variable is just an identifier. In fact, you could have multiple identifiers reference the exact same object. You are (generally) passing that reference, not any actual object.
2) The show/freeze function is going to stomp on the identifier name, either through named arguments in the function declaration or by referencing them through the arguments array.
I was trying to think if there was some clever way to use the arguments.callee or the stack property on an exception in Firefox... but I can't see anything that would expose the arguments as you desire.
What I would recommend is to simply add the name of the variable and its value to a simple object, and call one of the various jsDump methods (I prefer the one in QUnit):
function show(o) {
document.getElementById("viewer-table").innerHTML = QUnit.jsDump(o);
}
// actually use the method
show({"foo1":foo1});
There's no easy way to solve this as the called function simply doesn't know the original name of the variable. You couldn't solve this with reflection even (esp. in javascript) so you'll have to pass the name of the variable to the function too. To follow the link you posted:
function show(varObject)
{
for(name in varObject)
{
alert(name + ": " + varObject[name]);
// save both name and reference to the variable to a local "to observe array"
}
}
And call it with
var test = "xxx";
show({'test' : test});
Within the for loop you could add easy variable to a monitor array and update your gui in fixed time intervalls (you can't be notifed when a signle variable changes it's value. You need some kind of global monitor/observer which exactly you're trying to create).