I am receiving an ajax feed of documents that looks something like this (much simplified):
aDocs = [{title:'new doc', ext:'pdf'}, {title:'another', ext:'xlsx'}];
I am going to iterate through the aDocs array and display information about each doc, while adding some methods to each doc that will allow for modifying the HTML for display and making API calls to update the database.
I read here that in order to add methods to existing objects, you can use the __proto__
attribute. Something along the lines of:
function Doc(){}
Doc.prototype.getExt = function(){return this.ext}
Doc.prototype.getTitle = function(){return this.title}
for (var i=0; i<aDocs.length; i++){
aDocs[i].__proto__ = Doc.prototype
}
According to that article above,this isn't official javascript, isn't supported by IE (never will be), and will likely be deprecated in webkit browsers.
Here's an alternative stab at it:
function getExt(){ return this.ext }
function getTitle(){return this.title}
for (var i=0; i<aDocs.length; i++){
aDocs[i].getExt = getExt;
aDocs[i].getTitle = getTitle;
}
Is this second alternative viable and efficient? Or am I re-creating those functions and thereby creating redundant overhead?
Again the above examples are simplified (I know aDocs[i].ext
will solve the problem above, but my methods for display and API calls are more complicated).
I am receiving an ajax feed of documents that looks something like this (much simplified):
aDocs = [{title:'new doc', ext:'pdf'}, {title:'another', ext:'xlsx'}];
I am going to iterate through the aDocs array and display information about each doc, while adding some methods to each doc that will allow for modifying the HTML for display and making API calls to update the database.
I read here that in order to add methods to existing objects, you can use the __proto__
attribute. Something along the lines of:
function Doc(){}
Doc.prototype.getExt = function(){return this.ext}
Doc.prototype.getTitle = function(){return this.title}
for (var i=0; i<aDocs.length; i++){
aDocs[i].__proto__ = Doc.prototype
}
According to that article above,this isn't official javascript, isn't supported by IE (never will be), and will likely be deprecated in webkit browsers.
Here's an alternative stab at it:
function getExt(){ return this.ext }
function getTitle(){return this.title}
for (var i=0; i<aDocs.length; i++){
aDocs[i].getExt = getExt;
aDocs[i].getTitle = getTitle;
}
Is this second alternative viable and efficient? Or am I re-creating those functions and thereby creating redundant overhead?
Again the above examples are simplified (I know aDocs[i].ext
will solve the problem above, but my methods for display and API calls are more complicated).
- What is the problem with what you've tried? – Ruan Mendes Commented Mar 12, 2013 at 16:55
3 Answers
Reset to default 8Is this second alternative viable and efficient?
Yes.
Or am I re-creating those functions and thereby creating redundant overhead?
No, the functions are reused, not re-created. All of the objects will share the single copy of the getExt
and getTitle
functions. During the call to the functions from (say) aDocs[1]
, within the call, this
will refer to the object the function is attached to. (This only applies if you call it as part of an expression retrieving it from the object, e.g., var title = aDocs[1].getTitle();
)
Alternately, if you liked, you could create new objects which shared a prototype, and copy the properties from the aDocs
objects to the new objects, but you've asked about assigning new functions to existing objects, so...
Augmenting (adding methods to) the prototype is often the best way to go, but since you're dealing with object literals (or JSON.parse results), you'd have to either augment the Object.prototype
which is not done, or create a wrapper constructor, with the methods you need attached to its prototype. The problem will be: getting to grips with this
in that case... I'd leave things as they are: use the second approach: a simple loop will do just fine. Besides: prototype methods are (marginally) slower anyway...
The function objects themselves are being created ASAP (if they are defined in the global namespace, they're created as soon as the script is parsed). By simply looping through those objects, and assigning a reference to any function to each object, you're not creating additional functions at all.
Just try this:
var someObj = {name:'someObj'},
anotherObj = {name: 'anotherObj'},
someFunction = function()
{
console.log(this);
};
someObj.func = someFunction;
anotherObj.func = someFunction;
//or, shorter
someObj.func = anotherObj.func = someFunction;
//therefore:
console.log(someObj.func === anotherObj.func);//logs true! there is only 1 function object
someObj.func();//logs {name: 'someObj'}
anotherObj.func();//logs: {name: 'anotherObj'}
There have been posted many questions (and answers) that deal with this matter more in-depth, so if you're interested:
Objects and functions in javascript
Print subclass name instead of 'Class' when using John Resig's JavaScript Class inheritance implementation
What makes my.class.js so fast?
What are the differences between these three patterns of "class" definitions in JavaScript?
Are all more or less related to your question
In this case, I would just pass the object to the constructor of Doc;
function Doc(obj){
this.obj = obj;
}
Doc.prototype.getExt = function(){
return this.obj.ext;
}
Doc.prototype.getTitle = function(){
return this.obj.title;
}
var docs = [];
for (var i=0; i<aDocs.length; i++){
docs.push(new Doc(aDocs[i]));
}
There are two problems with your approach:
- You have to copy each method individually for every instance.
- Your "class" is not documented anywhere, making it a class makes it clearer that your object has those methods.