Unexpected shared data using JavaScript prototypal inheritance - javascript

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 =]

Related

What are all the properties available on a Component object in Svelte?

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.

How do I deal with prototype classes when working with typescript interfaces

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).

Various View Models Structure - How to create view models

I am new to knockout and readings it's tutorials for implementation.
I got to know about 2 different ways of writing view models in early chapters. I just need to know what is the difference between them.
I tried to figure out myself but may be not picking rights words.
Pdf i am refering to is Knockout PDF
There are several ways to create objects in javascript. The first one you're showing in your question is a literal. Another one is defining a constructor and invoking itt to get the object.
Yor AppViewModel is a constructor. If you need to use an instance of it as your viewmodel, you have to invoke the constructor, like this:
var vm = new AppViewModel();
ko.applyBindings(vm);
BTW, your fullName computed observable is incomplete. It's missing closing curly brakects, the second parameter, and closing parenthesis: }, self);

'document.id' documentation and the DOM

In the Mootools docs, regarding Element, I cannot catch the semantic area of the document element, for which I cannot find any reference in the Mootools Api. Is it just DOM Api?
For example $ accepts three parameters, the first of them is element. How do I define an element?
Further, the docs offer some advice: document.getElementById(‘foo’), document.id(‘foo’), $(‘foo’). So I understand document is a pretty important part of Mootools, but I do not understand where it overlaps to the classic DOM API, how far it is extended and so on.
So, MooTools has the concept of Types. Types are hashes built on top of either custom objects or by extending prototypes of Natives (Array, Element, String, Function, Number, to name a few) or appending methods to Natives (Date, Object).
The Element Type (http://mootools.net/core/docs/1.5.1/Element/Element) is the abstraction around HTMLElement as well as sub types like HTMLInputElement, all part of the DOM interface.
document itself is inheriting from Element to a degree - prototype methods available on any HTMLElement will be available to call on document as well, though they may not always be applicable. For example, addEvent will work and makes sense but tween or show etc won't.
Let's assume you mean document.id
Extending natives is considered harmful because it can result in unwanted side effects. Additionally, not every browser exposes the HTMLElement prototype for modification equally. Whereas in evergreen browsers (read, not IE 8 and lower), HTMLElement is OK to change, in IE6-7 it was not (read-only) and in IE8, it only extends some types of elements whereas others have no link to the augmented prototype chain.
So, imagine you have this:
<div id="foo">foo</div>
and a corresponding object:
var foo = document.getElementById('foo');
Since the constructor of foo is Element and the prototype of foo is Element.prototype, if you called foo.addEvent it will look up the chain, reach the Element.prototype.addEvent method and call it.
But because of IE6,7,8, the above may not work well or at all - MooTools devs chose a radical way of beating this issue by doing something simple: shortening the scope of the property lookup chain in these browsers.
This is done by actually setting a reference on the foo object itself pointing to all the methods and properties on the Element.prototype object.
you can think of doing it this way:
foo.addEvent = Element.prototype.addEvent.bind(foo);
so even if foo does not have access to the proto chain, it will still be able to call the method.
This so called 'extending' takes place the first time MooTools passes an element object.
So, in our case if in IE, you'd do:
foo = $(foo); // or document.id(foo);
Upon passing the element, it gets decorated with the references of the methods that you can now call
here's a better example:
var foo = document.getElementById('foo'), bar;
console.log(foo.hasOwnProperty('addEvent')); // false in all browsers
try {
foo.addEvent('click', bar = function(){});
}
catch(e){
console.log(e);
foo = $(foo);
foo.addEvent('click', bar = function(){});
console.log(foo.hasOwnProperty('addEvent')); // true in IE6,7,8
}
// by now it's already extended, so we can safely call it.
foo.removeEvent('click', bar);
further more: not only does document.id (which $ will alias to) enable proto methods use, it also sets up a Slick.uuid to recognise the element, which is then used to enable Element Storage via the data API (Element.prototype.store/retrieve/eliminate). This way, the Storage object has a unique key that maps to exactly one element in the DOM so you can stick stuff on there - it's the same implementation as jQuery's .data API.
FINALLY, document.getElementById is just JS api that gets you an element object. that's untouched by MooTools.
TL;DR; document.id(mixed) prepares elements for use with MooTools in a cross browser way and sets up storage.
Passing an element extends and returns the element object. Passing a string finds an element by ID if possible, then extends result and returns object.
You can also use new Element() constructor to create an element on document.createElement - as well as any HTMLElement you may have gotten from any QSA or DOM API.

Expand stateProperties in Fabric.js

I would like to expand all classes of Fabric.js with few properties that should be serializable as well. I was doing it this way:
var stateProps = fabric.Object.prototype.stateProperties;
stateProps.splice(0,0,"name", "id", "creator", "dateTimeCreated");
fabric.Object.prototype.stateProperties = stateProps;
It works for the object without the problem but "stateProperties" of all inherited classes are sometimes unfortunately "initialized" for the prototypes and my new properties are not mentioned.
Is there any way to call these lines before the prototypes of the inherited classes would be initialized?
The reason inherited "classes" don't get new properties is because they're built during declaration (when Fabric is initialized). So at that point, they're using original value of fabric.Object.prototype.stateProperties.
If your goal is to include properties in serialization output, don't forget that you can always use toJSON/toObject with additional "propertiesToInclude" argument:
object.toJSON([ 'foo', 'bar' ]);

Categories