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' ]);
Related
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.
Greetings dear community,
my goal is to spoof the screen object properties, but I can not just overwrite the properties by using:
window.screen[property] = number; or Object.defineProperty(...)
because these properties are read-only.
Therefore I wanted to kind of clone or recreate the screen object, manipulate the properties and then overwrite the whole window.screen object.
My attempt:
var clone = Object.create(Screen.prototype);
Object.assign(clone, window.screen);
console.log(clone);
The prototype is cloning well but not the properties.
After trying to get them with the Object.getOwnPropertyNames and Object.keys functions, which did not work either (example here), they have to be in the prototype.
So I tried this:
var clone = Object.create(Screen.prototype);
Object.assign(clone,Object.getPrototypeOf(window.screen));
console.log(clone);
which outputs the error "TypeError: 'get availWidth' called on an object that does not implement interface Screen."
Iterating with a for-in loop and assigning them does output the same error.
So it seems like I have to implement the interface Screen, even though I'm not sure if my plan is working after that. Perhaps there exists a simpler solution.
Other ideas:
I could assign the complete screen object as prototype (like that Object.create(screen)) and then set own properties on the object, but then the original values are still readable.
Maybe I also somehow can create an object by using Screen(...) interface?
Thanks for your help and ideas!
Seems like this is easily possible by the help of the Object.defineProperty() method, as long as the property is configurable.
var exampleProperty = 'colorDepth',
exampleValue = 55;
console.log("before:", screen[exampleProperty])
Object.defineProperty(screen, exampleProperty, {
// add descriptor properties here if desired
value: exampleValue
});
console.log("after:", screen[exampleProperty])
Using the new symbol type in ES6 you can set non-iterable properties on objects. However when using Knockout these symbols are not observed by default.
It is possible to bind a symbol's value, but it is never updated as it isn't added to the observable object.
Has anyone been able to work around this problem and force Knockout to observe symbols?
Looks like the observable plugin for Durandal is implemented similarly to the Knockout-ES5 plugin. When applied to a view model it's only going to create observables wrapped in a getter/setter for properties that are enumerable on the object.
observable.defineProperty doesn't accept enumerable as a param but it does have configuration: true. This means that we can use observable.defineProperty (which will make the property enumerable) but then immediately make the property non-enumerable like so...
Object.defineProperty(this, 'myProp', { enumerable: false });
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).
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 =]