best way to inherit funcs from another object

S

Stevo

I'm defining multiple objects that look basically like this, although
they'll have many more properties in the real case:

var myobj123={a:1,b:2,c:3,requires:"libv4"};
document.write(script tag to include v4 lib js file)

var myobj456={a:44.b:55,c:66,requires:"libv5"};
document.write(script tag to include v5 lib js file)

Just some objects with some properties. Nothing special going on there.
You see each of them has a requires field that specifies which version
of a library they need.

OK now we have the objects defined and the lib js files will define the
lib functions like this:

var libv4={};
libv4.func1=function(){};
libv4.func2=function(){};
libv4.func3=function(){};

var libv5={};
libv5.func1=function(){};
libv5.func2=function(){};
libv5.func3=function(){};

The two libs defined the same functions with the same names (in Java
terms you might say they implement the same interface). Now I want to
make the myobj123 and myobj456 retroactively inherit those functions. I
could do it like this:

myobj123.libfuncs=window[myobj123.requires];
myobj456.libfuncs=window[myobj456.requires];

and then I can call myobj123.libfuncs.func1(); which would use the v4
func, but myobj345.libfuncs.func1() would use the v5 func.

From a functionality point of view, this achieves what I need. I could
just go and build it like this and it'd work fine.

I'm pretty sure it's possible to achieve the same thing though without
having to have the libfuncs var pointing to one of the libs so that I
can just call myobj123.func1()

I tried this without success:

myobj123.prototype=window[myobj123.requires];

the func1 function isn't found with myobj123.func1() but in IE8's
developer tools I see that myobj123 has a prototype property that has a
func1 function. I suspect that I could call myobj123.prototype.func1()
but that's just the same as the libfuncs var really.

At this stage of development, I can rewrite to suit a better design as I
wanted to get the structure worked out before I write any real code.

The only limitations I have (caused by the existing project that I'm
building this into) is that the data objects have to exist first, and
the library code is included afterwards and then be added to the
objects. So creating the libraries and then creating the object
afterwards can't be done.
 
R

RobG

I'm defining multiple objects that look basically like this, although
they'll have many more properties in the real case:

var myobj123={a:1,b:2,c:3,requires:"libv4"};
document.write(script tag to include v4 lib js file)

var myobj456={a:44.b:55,c:66,requires:"libv5"};
document.write(script tag to include v5 lib js file)

That's a pretty inefficient, why not put all the scripts into one? It
will load (and be available to execute) much faster.

Just some objects with some properties. Nothing special going on there.
You see each of them has a requires field that specifies which version
of a library they need.

OK now we have the objects defined and the lib js files will define the
lib functions like this:

var libv4={};
libv4.func1=function(){};
libv4.func2=function(){};
libv4.func3=function(){};

Probably better as an object literal:

var libv4 = {
func1: function(){},
func2: function(){},
func3: function(){}
};
var libv5={};
libv5.func1=function(){};
libv5.func2=function(){};
libv5.func3=function(){};

The two libs defined the same functions with the same names (in Java
terms you might say they implement the same interface). Now I want to
make the myobj123 and myobj456 retroactively inherit those functions. I
could do it like this:

myobj123.libfuncs=window[myobj123.requires];
myobj456.libfuncs=window[myobj456.requires];

and then I can call myobj123.libfuncs.func1(); which would use the v4
func, but myobj345.libfuncs.func1() would use the v5 func.

Then why not just have those functions in a single script file and
assign them in the first place? If libv4 and libv5 are declared as
above, there is no conflict between them and you can add them as
properties to multiple objects (which is effectively what prototype
inheritance does).

From a functionality point of view, this achieves what I need. I could
just go and build it like this and it'd work fine.

I'm pretty sure it's possible to achieve the same thing though without
having to have the libfuncs var pointing to one of the libs so that I
can just call myobj123.func1()

I tried this without success:

myobj123.prototype=window[myobj123.requires];

the func1 function isn't found with myobj123.func1() but in IE8's
developer tools I see that myobj123 has a prototype property that has a
func1 function. I suspect that I could call myobj123.prototype.func1()
but that's just the same as the libfuncs var really.

Yes, you haven't implemented prototype inheritance properly - it works
using function objects (Functions), not plain objects. Objects
inherit via their internal [[prototype]] property from their
constructor's public prototype. But what you have done is all that is
required if you only want single instances of each myobj123 object.
You can still have multiple objects "inheriting" the same libv4 object
without issues, why complicate things with prototypes unnecessarily?.

To use prototype inheritance (you probably need something a bit
smarter, but this will do for now):

// Declare Libv4 as a function (add stuff to the body to initialise
instances):
function Libv4(obj) {
for (var p in obj) {
this[p] = obj[p];
}
};
Libv4.prototype = {
func1: function(){...},
func2: function(){...},
func3: function(){...}
};

// Create an instance and call an inherited function
var obj123 = new Libv4(myobj123);
obj123.func1();

You can do the same with libv5 and create instances of V5 objects that
inherit from V5.prototype.
At this stage of development, I can rewrite to suit a better design as I
wanted to get the structure worked out before I write any real code.

I'd re-design it so you don't use document.write to add extra
scripts. It's very inefficient and shows poor design in my view.
Don't bother with prototypes, just add your functions as object
properties. Instead of multiple instances of the same function,
consider creating single functions that do different things depending
on the parameters passed to them. If you have two functions with the
same name but which do completely different things, then your design
seems flawed.

The only limitations I have (caused by the existing project that I'm
building this into) is that the data objects have to exist first, and
the library code is included afterwards and then be added to the
objects.

Or you pass a parameter to the function to tell it what type of object
it's working on so it does the right thing. Without seeing more of
what you are trying to do, it's impossible to recommend one over the
other.
 
D

David Mark

I'm defining multiple objects that look basically like this, although
they'll have many more properties in the real case:
var myobj123={a:1,b:2,c:3,requires:"libv4"};
document.write(script tag to include v4 lib js file)
var myobj456={a:44.b:55,c:66,requires:"libv5"};
document.write(script tag to include v5 lib js file)

That's a pretty inefficient, why not put all the scripts into one?  It
will load (and be available to execute) much faster.
Just some objects with some properties. Nothing special going on there.
You see each of them has a requires field that specifies which version
of a library they need.
OK now we have the objects defined and the lib js files will define the
lib functions like this:
var libv4={};
libv4.func1=function(){};
libv4.func2=function(){};
libv4.func3=function(){};

Probably better as an object literal:

  var libv4 = {
    func1: function(){},
    func2: function(){},
    func3: function(){}
  };




var libv5={};
libv5.func1=function(){};
libv5.func2=function(){};
libv5.func3=function(){};
The two libs defined the same functions with the same names (in Java
terms you might say they implement the same interface). Now I want to
make the myobj123 and myobj456 retroactively inherit those functions. I
could do it like this:
myobj123.libfuncs=window[myobj123.requires];
myobj456.libfuncs=window[myobj456.requires];

and then I can call myobj123.libfuncs.func1(); which would use the v4
func, but myobj345.libfuncs.func1() would use the v5 func.

Then why not just have those functions in a single script file and
assign them in the first place? If libv4 and libv5 are declared as
above, there is no conflict between them and you can add them as
properties to multiple objects (which is effectively what prototype
inheritance does).
 From a functionality point of view, this achieves what I need. I could
just go and build it like this and it'd work fine.
I'm pretty sure it's possible to achieve the same thing though without
having to have the libfuncs var pointing to one of the libs so that I
can just call myobj123.func1()
I tried this without success:
myobj123.prototype=window[myobj123.requires];

the func1 function isn't found with myobj123.func1() but in IE8's
developer tools I see that myobj123 has a prototype property that has a
func1 function. I suspect that I could call myobj123.prototype.func1()
but that's just the same as the libfuncs var really.

Yes, you haven't implemented prototype inheritance properly - it works
using function objects (Functions), not plain objects.  Objects
inherit via their internal [[prototype]] property from their
constructor's public prototype.  But what you have done is all that is
required if you only want single instances of each myobj123 object.
You can still have multiple objects "inheriting" the same libv4 object
without issues, why complicate things with prototypes unnecessarily?.

To use prototype inheritance (you probably need something a bit
smarter, but this will do for now):

// Declare Libv4 as a function (add stuff to the body to initialise
instances):
function Libv4(obj) {
  for (var p in obj) {
    this[p] = obj[p];
  }};

Libv4.prototype = {
  func1: function(){...},
  func2: function(){...},
  func3: function(){...}

};

// Create an instance and call an inherited function
var obj123 = new Libv4(myobj123);
obj123.func1();

You can do the same with libv5 and create instances of V5 objects that
inherit from V5.prototype.
At this stage of development, I can rewrite to suit a better design as I
wanted to get the structure worked out before I write any real code.

I'd re-design it so you don't use document.write to add extra
scripts.  It's very inefficient and shows poor design in my view.

The poor design is adding scripts dynamically with script (at least in
production.) But if you are going to do it, document.write is a good
way. The alternatives are to add DOM nodes before the DOM is ready,
which is very dangerous. Not to mention that you would have to put
such scripts in the body (the HEAD must finish parsing before
mutation), which isn't always feasible.

[snip]
 
S

Stevo

RobG said:
That's a pretty inefficient, why not put all the scripts into one? It
will load (and be available to execute) much faster.

I'd love to be able to do that but it's just not possible. These little
nuggets of code above are part of a big dynamic page generation system
that decide at run-time that they want to include a "myobj123" and that
code will be dynamically created and the requires value is determined
also at run-time and could change. Only after that object is created
does it get to figure out which lib it needs to load to support itself.
I tried to get them to build that object and have all the lib functions
as part of it but they don't want that, and say that it will cause
unnecessary duplication. Each of the libs will only be loaded once.
There'll be a check to see if libv4 exists before document.write'ing the
script tag to load it.
Probably better as an object literal:

var libv4 = {
func1: function(){},
func2: function(){},
func3: function(){}
};

I had thought about doing it as an object literal but concluded that it
didn't bring any significant benefits and instead brought the potential
for future maintainers of the code to be confused and break it. Keeping
each function as a separate statement is a little easier to handle.
var libv5={};
libv5.func1=function(){};
libv5.func2=function(){};
libv5.func3=function(){};

The two libs defined the same functions with the same names (in Java
terms you might say they implement the same interface). Now I want to
make the myobj123 and myobj456 retroactively inherit those functions. I
could do it like this:

myobj123.libfuncs=window[myobj123.requires];
myobj456.libfuncs=window[myobj456.requires];

and then I can call myobj123.libfuncs.func1(); which would use the v4
func, but myobj345.libfuncs.func1() would use the v5 func.

Then why not just have those functions in a single script file and
assign them in the first place? If libv4 and libv5 are declared as
above, there is no conflict between them and you can add them as
properties to multiple objects (which is effectively what prototype
inheritance does).

If I understand correctly, you're again saying that the functions should
be part of the initial declaration of myobj123 and myobj456. That would
make this task of mine simpler, but they want to separate the data and
the functions. The object instance has only data in it and it's created
first. The lib has only functions in it that should be added to the
object after it's created and support it.
From a functionality point of view, this achieves what I need. I could
just go and build it like this and it'd work fine.

I'm pretty sure it's possible to achieve the same thing though without
having to have the libfuncs var pointing to one of the libs so that I
can just call myobj123.func1()

I tried this without success:

myobj123.prototype=window[myobj123.requires];

the func1 function isn't found with myobj123.func1() but in IE8's
developer tools I see that myobj123 has a prototype property that has a
func1 function. I suspect that I could call myobj123.prototype.func1()
but that's just the same as the libfuncs var really.

Yes, you haven't implemented prototype inheritance properly - it works
using function objects (Functions), not plain objects. Objects
inherit via their internal [[prototype]] property from their
constructor's public prototype. But what you have done is all that is
required if you only want single instances of each myobj123 object.
You can still have multiple objects "inheriting" the same libv4 object
without issues, why complicate things with prototypes unnecessarily?.

To use prototype inheritance (you probably need something a bit
smarter, but this will do for now):

// Declare Libv4 as a function (add stuff to the body to initialise
instances):
function Libv4(obj) {
for (var p in obj) {
this[p] = obj[p];
}
};
Libv4.prototype = {
func1: function(){...},
func2: function(){...},
func3: function(){...}
};

// Create an instance and call an inherited function
var obj123 = new Libv4(myobj123);
obj123.func1();

You can do the same with libv5 and create instances of V5 objects that
inherit from V5.prototype.

The only problem with that is that the lib is declared before the object
instance. Would it be possible to mix that up slightly so that the
prototype functions are added later? For example:

if(!window.Libv4){
window.Libv4=function(id,requires){
this.id=id;
this.requires=requires;
}
}
var obj123=new Libv4(123,"Libv4");
//now include libv4 for obj123 and below is what libv4 will do
Libv4.prototype.func1=function(){};
Libv4.prototype.func2=function(){};
Libv4.prototype.func3=function(){};

Would obj123 still inherit those functions func1, func2 and func3 even
though it was created as an instance of libv4 before they were added?
Maybe this is the way to go. It still meets the requirements of keeping
the code in the external file. The only difference being that I create
the actual Libv4 single object before the lib is loaded. I even check if
it already exists to avoid re-creating it.
I'd re-design it so you don't use document.write to add extra
scripts. It's very inefficient and shows poor design in my view.
Don't bother with prototypes, just add your functions as object
properties. Instead of multiple instances of the same function,
consider creating single functions that do different things depending
on the parameters passed to them. If you have two functions with the
same name but which do completely different things, then your design
seems flawed.

I'd like to redesign it, but these lib files are stored on a separate
server and will be maintained differently. The object instance part is
more fluid and is just a tiny chunk of code that's injected into the
page as it's dynamically built. One of the benefits they want is that at
any time they can deploy a new version of any of the libs, and all pages
old and new instantly see the updated code. They can also easily revert
back to an older version if a newer lib has issues in the live system. I
can see where they're coming from in terms of practicality and
maintenance, and to them that's more important and saves more money than
a few tricky inheritance challenges I have to deal with. It's not about
what's the most perfect design, it's about what design makes other parts
of the system have an easier time. I can see their point. If they only
need 8 people maintaining their system instead of 10, then they're
saving a 6 figure amount per year and the only cost is 100ms on load
time of a 6 second page and an extra $5k per year on data. They're gonna
make that choice as it might just push them into making a profit.
Or you pass a parameter to the function to tell it what type of object
it's working on so it does the right thing. Without seeing more of
what you are trying to do, it's impossible to recommend one over the
other.

I'm going to try that method mentioned above. See how that goes.

I did have another idea that I think I'll detail and see if you think
that's perhaps better. Of course this also isn't a perfect design and
has it's inefficiencies.

//create obj123 in the original way
var obj123={a:1,b:2,c:3,requires:"libv4"};
//create an array of objects that need libv4'ing
if(!window.needsLibv4)
window.needsLibv4=[];
//add this obj123 to that array
window.needsLibv4[needsLibv4.length]=obj123;//libv4 has a customer

//now load libv4 and below is what libv4 will do to obj123

//if libv4 exists and has objects waiting
if(window.needsLibv4 && needsLibv4.length>0){
//loop through them
for(var i=0;i<needsLibv4.length;i++){
//get the first object in the array
var obj=needsLibv4;
//if it hasn't already been handled
if(obj!=null){
//handle it now - add all the functions to it
obj.func1=function(){};
obj.func2=function(){};
obj.func3=function(){};
//let any future load of libv4 know not to re-do this object
needsLibv4=null;
}
}
}

That libv4 loop would most likely be in a function itself for variable
scope protection and so that it can be called by subsequent objects that
need libv4 functions but realize that they don't need to reload the
libv4 file, instead just call the function.
 
S

Stevo

RobG said:
To use prototype inheritance (you probably need something a bit
smarter, but this will do for now):

// Declare Libv4 as a function (add stuff to the body to initialise
instances):
function Libv4(obj) {
for (var p in obj) {
this[p] = obj[p];
}
};
Libv4.prototype = {
func1: function(){...},
func2: function(){...},
func3: function(){...}
};

// Create an instance and call an inherited function
var obj123 = new Libv4(myobj123);
obj123.func1();

Based on the above, I've restructured things and got it basically
working and still meeting the initial requirements of keeping the
functions and data object separate, with the data object being defined
first. Here it is:

if(!window.Libv4){
window.Libv4=function(i,n,r){
this.id=i; this.name=n; this.requires=r;
}
}
else document.write tag to load Libv4 js
window.obj123=new Libv4(123,"me","Libv4");

If the Libv4 file is loaded then it runs the code from it shown here:

Libv4.prototype.func1=function(){};
Libv4.prototype.func2=function(){};
Libv4.prototype.func3=function(){};

Now a call to obj123.func1() works.
 
R

RobG

RobG said:
To use prototype inheritance (you probably need something a bit
smarter, but this will do for now):
// Declare Libv4 as a function (add stuff to the body to initialise
instances):
function Libv4(obj) {
for (var p in obj) {
this[p] = obj[p];
}
};
Libv4.prototype = {
func1: function(){...},
func2: function(){...},
func3: function(){...}
};
// Create an instance and call an inherited function
var obj123 = new Libv4(myobj123);
obj123.func1();

Based on the above, I've restructured things and got it basically
working and still meeting the initial requirements of keeping the
functions and data object separate, with the data object being defined
first. Here it is:

if(!window.Libv4){

Since you are dealing with native objects use typeof, not simple
boolean conversion. You seem to want fully qualified paths to native
objects so don't use window - get a reference to the global object and
use that:

var globalObj = (function(){return this;})();
if (typeof globalObj.Libv4 != 'function') {

Now you *know* that globalObj will be a reference to the global object
(which is effectively the same as the window object in browsers), you
don't have to worry that some other window identifier on the scope
chain has shadowed the one you wanted.
window.Libv4=function(i,n,r){
this.id=i; this.name=n; this.requires=r;
}}

I'd use something more like the generic constructor I posted above -
it doesn't care what the properties are, they are defined
independently (helps avoid name clashes) and the constructor just
copies them over. You may want to add a "hasOwnProperty" test to
filter out inherited, enumerable properties, there are issues with
that too:

<URL: http://groups.google.com/group/comp.lang.javascript/msg/786c00c19e7f3ab6
else document.write tag to load Libv4 js

That doesn't quite make sense to me - if it doesn't exist, you create
it. If it does exist, you load the script (presumably replacing what
is there)?

The simplest method is to load the scripts up front, then, in a
subsequent script element, use the loaded script. You can use a
scheme like:

<script ...>
// work out which scripts to load
// load using document.write
</script>
<!-- loaded scripts will end up here -->
<script...>
// Use loaded scripts
</script>

Whatever strategy you employ, you have to wait for the script to load
(possibly quite some time) and be executed (probably very quick)
before trying to use the code in it.
window.obj123=new Libv4(123,"me","Libv4");

If the Libv4 file is loaded then it runs the code from it shown here:

Libv4.prototype.func1=function(){};
Libv4.prototype.func2=function(){};
Libv4.prototype.func3=function(){};

Now a call to obj123.func1() works.

Yes, that's prototype inheritance. Since you seem to want to define
the data and function components of obj123 separately, you'll need a
scheme to prevent name clashes, maybe:

1. Prefix all functions with "fn_" and make it known it is reserved
for methods, or do something similar for data properties, or both.

2. Put the data on a data property like:

var obj123.data = {...};

Which is also helps if you want to do stuff with just the data part
(say pass a reference or replace it), without messing with the rest of
the object (which may not matter to you anyway).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top