import ItemPanel from '../Panel/ItemPanel.svelte';
If I log console.log(ItemPanel), I get the class definition:
class ItemPanel extends SvelteComponentDev {
constructor(options) {
super(options);
init(
this,
options
...
But if I console.log(ItemPanel.name), I simply get "ItemPanel" returned to me.
I use the panel's name in a modal component that receives components to open, and this is how I've been IDing them for special functionality. But then I realized that I lose that functionality on production build because I'm tensor()ing and that changes the component's name in production. I'm hoping to log all properties to see if there's one that sticks between both dev and production mode.
I don't think this is a Svelte-specific question, though of course I could be mistaken.
Answering what you actually asked, you can get the properties of an object (including a function object) via Object.getOwnPropertyNames (for the ones with string names) and Object.getOwnPropertySymbols (for the ones with Symbol names). (In contrast, Object.keys only gives you a subset of what getOwnPropertyNames gives you: the names of own enumerable properties with string names. [getOwnPropertyNames includes non-enumerable ones.]) To get inherited properties, use Object.getPrototypeOf and then use the first two functions again. Rinse, repeat until you reach Object.prototype.
But getting to your underlying requirement:
ItemPanel in your code is a constructor function. Functions get their names by how they're defined. A constructor function created via a named class declaration or expression (yours looks like a declaration) gets its name from the name given for the class. The name property of a function gives the name of the function.
If you're minifying the code in some way such that name is no longer what you're looking for, and you need some similar unique identifier, you can add one using a static field:
class ItemPanel extends SvelteComponentDev {
static id = "ItemPanel";
// ...
}
Of course, that means repeating yourself.
But stepping back a step:
I use the panel's name in a modal component that receives components to open...
In that situation I'd use the actual function rather than its name.
Related
Is it possible to create an element if you have its constructor but don't know its tag name?
Example:
class CustomElement extends HTMLElement {}
customElements.define(genRandomString(), CustomElement);
Is it possible to create a new instance of CustomElement? Or can you obtain its tag name in any way?
I'm asking this because I'm not sure what's the correct way to pass custom elements to functions that need them: do I need to pass around both the name and the constructor, in case one may need to either create an element (which requires the name) or to check whether an existing element is of this kind (which requires the constructor)?
Is it possible to create an element if you have its constructor but don't know its tag name?
If you have access to the constructor (like you said you have), you can just use
const instance = new CustomElement();
Please note that this might fail if the constructor doesn't conform to Custom Element constructor constraints.
Is this what you are asking for:
let foo = "bar";
window[ genRandomString() ] = foo;
And then you want to know what getRandomString produced?
Only when you monitor window can you capture what is added to it.
Same with WebComponents, only when you hook into customElements.define can you record what names are used.
In other words: mess with its prototype and potentially breaking its default execution.
But this only works from the moment you are in control; you could have missed all Web Components created already, at that time.
Can you explain WHY you want to do this?
I am reading about getters and setters in javascript. I would like to know if there is a difference between this two ways of coding with and without setters
first way, without setters.
>obj1 = {
arr: [];
}
>obj1.arr.push('first')
>obj1.arr
[ 'first' ]
Second way, with setters.
>obj2 = {
set add(data) {
this.arr.push(data);
},
arr: []
}
>obj2.add = 'first'
>obj2.arr
[ 'first' ]
The setter syntax in your example does not really prevent the client code to still add a value using the direct push call as in the first code block. So the difference is that you just added another way to do the same thing.
To make a fair comparison, you would have to define the same method in both alternatives: once as a normal method and once as a setter method, and then the difference is just the syntax how the argument is passed to the method, either with obj.add('first') or obj.add = 'first'.
In this actual case I would vote against the setter, because it gives the false impression that if you "assign" another value, the first assigned value is overwritten:
obj.add = 'first';
obj.add = 'second';
... but obviously this is not the case: both values exist in the object now.
First, The set Syntax bind an object property to a defined function. In this particular example, there is no difference between two codes, but let's say for example you want to check if the value is negative before adding it to the array, so you can use set to Encapsulate that behavior.
So basically, using setter is only to add additional encapsulated behavior to the functions of the objects.
The way of accessing the array index called bracket notation. it is equal to dot notation, except the bracket notation allows you to set new properties to objects or arrays dynamically.
Hope this help you.
I think difference only about "how it looks like". Using setters it's closest way for understanding for people who came to js from object oriented languages.
The getter/setter property is not the same as "normal" instance property, one is called "named data property", the other is called "named accessor property".
Please let met quote below part of documents from the ECMAScript 5.1.
https://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1
An Object is a collection of properties. Each property is either a
named data property, a named accessor property, or an internal
property:
A named data property associates a name with an ECMAScript language
value and a set of Boolean attributes.
A named accessor property associates a name with one or two accessor
functions, and a set of Boolean attributes. The accessor functions are
used to store or retrieve an ECMAScript language value that is
associated with the property.
An internal property has no name and is not directly accessible via
ECMAScript language operators. Internal properties exist purely for
specification purposes.
There are two kinds of access for named (non-internal) properties: get
and put, corresponding to retrieval and assignment, respectively.
And
If the value of an attribute is not explicitly specified by this
specification for a named property, the default value defined in Table
7 is used.
Let's suggest that I have a data library that handles most of my object management.
For each resource it allows me to choose a base class to which it adds it's own prototype functions to.
So for example If I have,
interface IJob
{
openJob();
}
class Job : IJob
{
openJob() => {console.log('open');}
}
then create my Job via
Store.job.create();
it returns a instance of the class but it also decorates it with prototype functions like .save(), .update(), etc
The problem is that if I try to use .save() on the job instance, it's undefined because the interface doesn't define it. Now if I do define it, it expects me to define .save/.update in the class which I don't really want to do because the store is already adding prototype functions to the class.
Is there a best way to handle this?
For reference I'm trying to use js-data as my data store library.
Now if I do define it, it expects me to define .save/.update in the class which I don't really want to do because the store is already adding prototype functions to the class.
What are you looking for is mixins. And there are official links for mixins: https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Mixins.md which shows that you do need to declare these in the class even though you don't define them (and they get mixed in).
Use case:
I have a base class from which many other classes inherit.
The base class is called HSManagedObject.
I have another class called HSContext that keeps a dictionary of HSManagedObjects where the keys are the names of the various subclasses and the values are lists of the instances of those subclasses. I insert them like so:
insertObject(object: HSManagedObject) {
this.projectObjects[object.key()].push(object)
}
Because class names go away when I minify my javascript (they all become t), I added a static property to each of those classes called key that uniquely identifies the class in question.
When I add an object to the dictionary, I would like to infer the class name of that object from the instance. Is there a way to get the static key variable just from the instance when I don't know which subclass it belongs to?
Currently I am adding an instance method to each of the subclasses called key() that returns the class's static key value and calling the instance method to get the class value. It seems like I shouldn't need to do this though. So in all of my subclasses I have some code like this:
static key = "HSRule";
key() {
return HSRule.key;
}
This may be tricky. If TypeScript is compiled down to JavaScript, the "classes" become simple variables and the static vars are just assigned to them.
You could try something like this:
Object.getPrototypeOf(object).constructor.key
getPrototypeOf() Reference
Coming from a Java background, I expect properties in the base class of an instance of a class to be unique from other class instances that use the same base class.
In javascript, any properties stored in "base class" appear to be shared between various instances of that "base class". For instance, see here:
http://jsfiddle.net/4waQV/
As you can see, BaseView.settings is accessed via both ViewOne and ViewTwo. Changing a value in BaseView.settings in one instance affects the value in the other instance.
If I move settings: {} out of BaseView and into ViewOne and ViewTwo, everything works the way I expect.
http://jsfiddle.net/4waQV/1/
However, I don't want to clutter up ViewOne and ViewTwo with extra properties. So I can dynamically create this.settings inside BaseView.setProp():
http://jsfiddle.net/4waQV/2/
Are there better ways to deal with this, or is this a good solution?
Note that I'm using Backbone.JS views in this example, but I expect than any javascript prototype inheritance solution would result similarly. You can see that Backbone uses fairly typical methods of creating prototypical inheritance:
https://github.com/documentcloud/backbone/blob/0.3.3/backbone.js#L870
https://github.com/documentcloud/backbone/blob/0.3.3/backbone.js#L955
The problem here is that settings is inherited from BaseView; inherited, not copied. If it were a string value it would be essentially copied, but in javascript arrays and objects are passed by reference, not by value, so when the object instantiates it ends up pointing at the same object.
The fix is to create an initialize method in your BaseView and add this line:
this.settings = {};
Then of course you'll want to make sure you call the BaseView initialize from each of your subviews. You can do that with:
BaseView.prototype.initialize.apply(this, arguments);
e.g. http://jsfiddle.net/taxilian/PDmN8/1/
Note that this method of initializing members needs to be done on all array or object members or you'll have the same issue. You could also create a constructor and do it there, but I've never been really clear on how those work in Backbone classes and haven't taken the time to really sit down and figure it out =]