I want to turn a plain JavaScript object into one with a prototype etc, without cloning the object. Is this possible?
Essentially, instead of this:
var MyClass = function(fromObj) {
this.propA = fromObj.propA;
this.propB = fromObj.propB;
...
}
inherit (SuperClass, MyClass);
I would like to:
var MyClass = function(fromObj) {
this = fromObj;
}
inherit (SuperClass, MyClass);
To be extra clear: I would like the object returned from the constructor to be the same object that was passed in (not a duplicate, not a clone).
Is there a way to achieve this? Or a better way to describe what I'm asking for? :)
I'd like this for two reasons:
We're loading a lot of objects, and speed and memory may start to matter.
There are lots of places where the "plain old javascript objects" are used, and it may be hard to make sure they all point to the new instantiated object.
I guess you want to do this so that the objects created by JSON.parse are instances of something other than Object.
One option is to assign a new [[Prototype]] that is from the specified constructor using Object.setPrototypeOf, however there are performance warnings for this on MDN (I have no idea on the validity of the claims).
A more efficient solution might be to create "wrapper" objects and attach those created by JSON as a property. This approach is used by a number of DOM libraries and avoids the possibility of property names from the JSON data clashing with method names of the object (e.g. the DOM libraries can use methods with the same name and characteristics as DOM methods, but don't overwrite or clash with them).
Data could be held in a closure so that only getters and setters defined by the constructor can access it.
Related
When instance function are called in a class each instance of object get own copy of function but in prototype method and static method no copy is created , they belong to class, so if they both doesn't create a copy of their function, so why do we have static function if we can simply use prototype method if we don't want to copy??
I am a little bit confuse, if anyone can explain it will be a great help
In order to use a prototype/instance method, you need to either have an instance of an object or specifically access the type's .prototype. For methods that don't require an instance, a static method provides simpler syntax. Think of the String.fromCharCode() method as an example. It wouldn't make sense to say:
let str = "dummy string".fromCharCode(127);
The extra string instance there is just a distraction from what you're really trying to do:
let str = String.fromCharCode(127);
This applies good programming practices of reduced coupling (not requiring an instance in order to invoke a method that doesn't need it) and information hiding (by not exposing a method on instances of objects which doesn't pertain to those specific objects).
A static method does not exist on instances. Prototype methods do. So, if you want to call someArr.filter(x => x > 5) that would be an instance method that works on the given array.
An example of astatic method is Array.isArray(someArr). It makes very little sense to make the static method an instance method because you'd need an instance before calling it. That would lead to code like someArr.isArray(someArr) which is illogical - you need an array to check if something is an array. And that can very easily be fail spectacularly if someArr is not in fact an array:
const someArr = {
isArray() { return true; },
filter() { return "I am not an array"; },
};
console.log(someArr.isArray(someArr));
console.log(someArr.filter(x => x > 5));
Yes, that example is indeed highly illogical in order to highlight why it is weird. Assuming .isArray() was an instance method, you could create a new array in order to use it to call [].isArray(someArr). But that method does not require any instance data. The object created exists only to give you access to the method and is discarded immediately afterwards. That design is still not sensible.
Both static methods and prototype methods exist independent from any instances. The difference is that a prototype method expects to be called on an instance, i.e. to have an instance passed as the this argument, whereas the static method does not require an instance and expects none.
Even without placing them anywhere on the class, we can see this distinction in the following example:
function myStaticMethod(arg) {
console.log('Doing something with '+arg);
}
function myMethod(arg) {
console.log('Doing something with '+this+' and '+arg);
}
const myInstance = new MyClass();
myStaticMethod('value');
myMethod.call(myInstance, 'value');
Now the .call() syntax is not very ergonomic, we prefer myInstance.myMethod('value'), so that is why we place the method on the prototype object of the class, having it inherited by all instances.
For static methods, this is not necessary. They don't need an instance, we don't want to call them on an instance, we want to call them as MyClass.myStaticMethod('value') so that is where we place them. We could put them on the prototype as well, but that would lead to confusion (myInstance.myStaticMethod()), name collisions, and unncessarily long invocations (MyClass.prototype.myStaticMethod()). It's imaginable to write new MyClass().myStaticMethod(), but there you would unnecessarily create an instance that is not required (and it might not even be possible to create).
We can create the object in JavaScript through three ways :-
1.) var obj = {name:'John', age:30, gender:'male'};//using object literal
2.) var a = new Test();// using constructor function
3.) var obj = Object.create(null);// using Object.create() method
But my question is, when we have to use object literal, constructor function and Object.create() method. And also the difference between these three.
Like in which case or which kind of requirement we can use one of these according to that requirement.
And give me some real project example.
The most basic and clearest way to make an object is with the object literal syntax.
However that is not always practical, say if you want to make many objects with the same property keys just with different values, it is a lot quicker and less verbose to use the constructor function.
And regarding Object.create(), the main usage for that is to inherit the prototype of another object and not made to create its own values (even though it is possible.)
perf
Why do we build a prototype inheritance chain rather then using object composition. Looking up through the prototype for each step in the chain get's expensive.
Here is some dummy example code :
var lower = {
"foo": "bar"
};
var upper = {
"bar": "foo"
};
var chained = Object.create(lower, pd(upper));
var chainedPrototype = Object.create(chained);
var combinedPrototype = Object.create(pd.merge(lower, upper));
var o1 = Object.create(chainedPrototypes);
var o2 = Object.create(combinedPrototypes);
uses pd because property descriptors are verbose as hell.
o2.foo is faster then o1.foo since it only goes up two prototype chain rather then three.
Since travelling up the prototype chain is expensive why do we construct one instead of using object composition?
Another better example would be :
var Element = {
// Element methods
}
var Node = {
// Node methods
}
var setUpChain = Object.create(Element, pd(Node));
var chained = Object.create(setUpChain);
var combined = Object.create(pd.merge(Node, Element));
document.createChainedElement = function() {
return Object.create(chained);
}
document.createCombinedElement = function() {
return Object.create(combined);
}
I do not see any code merging prototype objects for efficiency. I see a lot of code building chained prototypes. Why is the latter more popular?
The only reason I can think of is using Object.isPrototypeOf to test for individual prototypes in your chain.
Apart from isPrototypeOf are there clear advantages to using inheritance over composition?
The main reason would have to be changes to the prototype object. A change to an ancestor object will be reflected across the entire chain. This could, conceivably, be a benefit. Though I can't immediately think of any real-world instances, I think embracing this dynamic nature could provide a dynamic that other (read: class-based) languages simply don't provide.
Objects further up the prototype chain could evolve as needed across the lifetime of an application, and those changes would be reflected across all descendant objects. This could be easily combined with JavaScript's functions as first-class objects to dynamically modify functionality as needed.
That said, if this functionality is not necessary, there is no reason to use the prototype chain over composition.
Well, consider what would happen if lower or upper changed. The combined prototype wouldn't reflect that change since you've created a new object by copying properties from them.
For many situations that would be fine, but it's sure not as dynamic as actually constructing proper prototype chains for your objects.
Here are some benefits I can think of in order of importance
Memory usage
By using the prototype, you create shared properties. Your approach copies all the values to each object.
Upfront cost of setting up objects
Thought you are saving a little bit of time later, you are incurring the cost of copying properties when you set up the object. It'd be nice for you to account for that in your performance tests. This is a benefit that may be outweighed if you read a lot more than you set up your objects.
instanceOf
Good code doesn't use instanceOf, but sometimes you can't make all your code perfect, so why break a language feature?
Dynamically changing the prototype
Most people will claim that they never need this (like me), but many of us have extended Array.prototype after instantiating some arrays (not that you should do it). With the copy properties approach you lose the reference to the original object.
Unashamed plug: http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Last Note If you this is actually a bottleneck in an app, I would not be reluctant to use it for the objects in question
In JavaScript, why would one want to attach properties directly to the constructor?
var Human = function() {};
Human.specie = "Homo Sapience";
I've got this question after looking at CoffeeScript‘s __extend helper function, which contains, among the lines:
for ( var key in parent ) {
if ( __hasProp.call( parent, key ) ) child[key] = parent[key];
}
which copies properties / methods to the subclassed object directly from the constructor object. But why would anybody do that?
Thanks!
(Edit: In its original form, the question asked about attaching properties to classes vs. attaching them to prototypes, so that's what I'm responding to.)
It's really more a matter of convention than anything else. If you write
Human::specie = "Homo sapiens"
(where Human::specie is CoffeeScript shorthand for Human.prototype.specie) then declare jane = new Human, then jane.specie will be "Homo sapiens" (unless you specifically set jane.specie to something else). In this case, that sounds desirable.
But in other cases, having a property shared across a large number of prototypes makes your code harder to understand. Let's say that you have a Logger class with a config object. If you attached that object to the prototype, then you could write code like this:
log = new Logger
log.config.destination = './foo'
This would change the destination of all Logger instances to './foo', because there's only one config object. If you want config to apply to all Logger instances, then you should attach it to the class proper, removing the ambiguity from the code above:
log = new Logger
Logger.config.destination = './foo'
In a game say you have an object called world. However there will only ever be one world in the game. This is theoretically the reason you would do this.
In short the answer to the question posted is name spacing. There are certain values that may have sense to be shared across your program and that semantically have to do with certain class. These functions and values could be just put in some variables, but attaching them to constructor function is practical in order to namespace them.
The best example is JavaScript Math class (for purists, I know it's not really a class, it's an object):
// There are constants
Math.E
Math.PI
Math.SQRT2
// And there are also methods
Math.ceil
Math.cos
Math.sin
So the methods and values (saved in constants) are always the same and they don't depend on instance that they are being called on and it makes no sense to have them on instances.
I want to write some Javascript classes which extend DOM nodes (so that I can then insert instances of my class directly into the DOM), but am having difficulty finding out which class/prototype I should inherit from.
E.g.:
function myExtendedElement() {
this.superclass = ClassA;
this.superclass();
delete this.superclass;
}
But what should ClassA be?
It's not a good idea to do this.
First of all, to inherit from DOM element, you need to have access to that element's prototype. The problem is that not all browsers provide access to prototypes of DOM elements. Newer Gecko and WebKit -based clients, for example, expose some of these prototypes as global objects - HTMLDivElement, HTMLElement, Element, Node, etc.
For example, plain DIV element usually has a prototype chain similar to:
HTMLDivElement.prototype -> HTMLElement.prototype -> Element.prototype
-> Node.prototype -> Object.prototype -> null
You can access any of them and extend or inherit from as desired. But again, even though you can, I strongly advise not to.
When browser doesn't expose these prototypes, you're pretty much out of luck. You can try retrieving them by following constructor property of DOM element itself -
document.createElement('div').constructor;
- but then there's no guarantee that element has constructor property (e.g. IE6 doesn't) and even if it does, that this property references "correct" object. If, after all, constructor does reference correct object, there's still no guarantee that this objects is allowed to be augmented at all. The truth is that host objects are allowed to implement completely bizarre behavior and do not even have to follow rules that native JS objects follow (you can find dozens of such examples in real life).
Second reason you want to avoid inheriting from DOM element prototypes is that mechanism of such inheritance is not really specified anywhere; it could be quirky, unpredictable and overall fragile and unreliable.
Yes, you can create a constructor that would initialize objects with proper prototype chain (i.e. having DOM prototype in it):
function MyDivElement(){}
MyDivElement.prototype = HTMLDivElement.prototype;
var myDiv = new MyDivElement();
typeof myDiv.appendChild; // "function"
- but this is as much as it goes, and usefulness of this whole approach becomes limited by having certain methods in prototype and nothing else -
typeof myDivElement.nodeName; // "undefined"
myDivElement.innerHTML = '<span>foo<\/span>';
myDivElement.childNodes; // Error
Until some standard specifies exact mechanism for inheriting from DOM prototypes (and browsers actually implement that mechanism), it's best to leave them alone, and perhaps try alternative approach - e.g. wrapper or decorator patterns rather than prototype one :)
Old Q but there's a better answer than "Do" or "Don't" now that IE6 is mostly defunct. First of all prototyping core ECMA endpoint-inheritance constructors like 'Array' is pretty harmless and useful if you do it properly and test to avoid breaking existing methods. Definitely stay away from Object and think real hard before messing with Function, however.
If you're sharing code between a lot of people/authors, or dealing with DOM uncertainty, however, it's typically better to create adapter/wrapper objects with a new factory method to use in an inheritance-scheme.
In this case I wrote document.createExtEl to create wrapped DOM elements whose accessible properties are all available via prototype.
Using the following, your "superclass" for divs would be HTMLExtDivElement (in this case globally available - ew, but it's just an example). All references to the original HTMLElement instance's available properties live inside the wrapper's prototype. Note: some old IE properties can't be passed as references or even accessed without throwing errors (awesome), which is what the try/catch is for.
You could normalize common properties by adding logic to put missing or standardized properties in right after the loop wraps instance-available properties but I'll leave that to you.
Now for the love of Pete, don't ever use my code to write some cascading 16-times inheritance foolishness and then implement in some ironically popular library we're all forced to deal with or I will hunt you down and loudly quote "Design Patterns" at you while throwing rotten fruit.
//Implementation just like document.createElement()
//document.createExtEl('div').tagName === 'DIV'
document.createExtEl = ( function(){ //returns a function below
var htmlTags = ['div','a'], //... add all the element tags you care to make extendable here
constructorMap = {},
i = htmlTags.length;
while(i--){
thisTag = htmlTags[i].toLowerCase();
constructorMap[ thisTag ] = function(){
var elObj = document.createElement(thisTag),
thisProto = this.constructor.prototype,
constructorName = 'HTMLExt' + thisTag.charAt(0).toUpperCase() + thisTag.slice(1) + 'Element';
alert(constructorName);
window[constructorName] = this.constructor; //adds a global reference you can access the new constructor from.
for(var x in elObj){ try{ thisProto[x] = elObj[x]; } catch(e){} }
}
}
//all of the above executes once and returned function accesses via closure
return function(tagName){
return new constructorMap[tagName.toLowerCase()]();
}
} )()
//Now in the case of a superclass/constructor for div, you could use HTMLExtDivElement globally
In 2020, you can easily create a custom element by extending HTML elements.
class AppDrawer extends HTMLElement {...}
window.customElements.define('app-drawer', AppDrawer);
// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('app-drawer', class extends HTMLElement {...});
More info and reference: Custom Elements
You can simply add new functions to the DOM prototypes, eg.
Element.prototype.myNameSpaceSomeFunction = function(...){...}
Then myNameSpaceSomeFunction will exist on all elements.
I've found a hack that works... at least, it enables me to access the extended object properties via the DOM element and vice versa. But it's hardly elegant.
var DOMelement = document.getElementById('myID'); // or $('#myID')[0]; in jQuery
DOMelement.extended = new extensionClass(this);
function extensionClass(element) {
this.element = element;
...
}